Passed
Pull Request — master (#888)
by Tobias
01:50
created

Client::sendRequest()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 17
nc 8
nop 1
dl 0
loc 32
rs 8.5806
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright 2017 Facebook, Inc.
4
 *
5
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
6
 * use, copy, modify, and distribute this software in source code or binary
7
 * form for use in connection with the web services and APIs provided by
8
 * Facebook.
9
 *
10
 * As with any software that integrates with the Facebook platform, your use
11
 * of this software is subject to the Facebook Developer Principles and
12
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
13
 * shall be included in all copies or substantial portions of the software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
namespace Facebook;
25
26
use Facebook\Exception\SDKException;
27
use Http\Client\HttpClient;
28
use Http\Discovery\HttpClientDiscovery;
29
use Http\Discovery\MessageFactoryDiscovery;
30
31
/**
32
 *
33
 * @package Facebook
34
 */
35
class Client
36
{
37
    /**
38
     * @const string Production Graph API URL.
39
     */
40
    const BASE_GRAPH_URL = 'https://graph.facebook.com';
41
42
    /**
43
     * @const string Graph API URL for video uploads.
44
     */
45
    const BASE_GRAPH_VIDEO_URL = 'https://graph-video.facebook.com';
46
47
    /**
48
     * @const string Beta Graph API URL.
49
     */
50
    const BASE_GRAPH_URL_BETA = 'https://graph.beta.facebook.com';
51
52
    /**
53
     * @const string Beta Graph API URL for video uploads.
54
     */
55
    const BASE_GRAPH_VIDEO_URL_BETA = 'https://graph-video.beta.facebook.com';
56
57
    /**
58
     * @const int The timeout in seconds for a normal request.
59
     */
60
    const DEFAULT_REQUEST_TIMEOUT = 60;
61
62
    /**
63
     * @const int The timeout in seconds for a request that contains file uploads.
64
     */
65
    const DEFAULT_FILE_UPLOAD_REQUEST_TIMEOUT = 3600;
66
67
    /**
68
     * @const int The timeout in seconds for a request that contains video uploads.
69
     */
70
    const DEFAULT_VIDEO_UPLOAD_REQUEST_TIMEOUT = 7200;
71
72
    /**
73
     * @var bool Toggle to use Graph beta url.
74
     */
75
    protected $enableBetaMode = false;
76
77
    /**
78
     * @var HttpClient HTTP client handler.
79
     */
80
    protected $httpClient;
81
82
    /**
83
     * @var int The number of calls that have been made to Graph.
84
     */
85
    public static $requestCount = 0;
86
87
    /**
88
     * Instantiates a new FacebookClient object.
89
     *
90
     * @param HttpClient|null $httpClient
91
     * @param boolean         $enableBeta
92
     */
93
    public function __construct(HttpClient $httpClient = null, $enableBeta = false)
94
    {
95
        $this->httpClient = $httpClient ?: HttpClientDiscovery::find();
96
        $this->enableBetaMode = $enableBeta;
97
    }
98
99
    /**
100
     * Sets the HTTP client handler.
101
     *
102
     * @param HttpClient $httpClient
103
     */
104
    public function setHttpClient(HttpClient $httpClient)
105
    {
106
        $this->httpClient = $httpClient;
107
    }
108
109
    /**
110
     * Returns the HTTP client handler.
111
     *
112
     * @return HttpClient
113
     */
114
    public function getHttpClient()
115
    {
116
        return $this->httpClient;
117
    }
118
119
    /**
120
     * Toggle beta mode.
121
     *
122
     * @param boolean $betaMode
123
     */
124
    public function enableBetaMode($betaMode = true)
125
    {
126
        $this->enableBetaMode = $betaMode;
127
    }
128
129
    /**
130
     * Returns the base Graph URL.
131
     *
132
     * @param boolean $postToVideoUrl Post to the video API if videos are being uploaded.
133
     *
134
     * @return string
135
     */
136
    public function getBaseGraphUrl($postToVideoUrl = false)
137
    {
138
        if ($postToVideoUrl) {
139
            return $this->enableBetaMode ? static::BASE_GRAPH_VIDEO_URL_BETA : static::BASE_GRAPH_VIDEO_URL;
140
        }
141
142
        return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL;
143
    }
144
145
    /**
146
     * Prepares the request for sending to the client handler.
147
     *
148
     * @param Request $request
149
     *
150
     * @return array
151
     */
152
    public function prepareRequestMessage(Request $request)
153
    {
154
        $postToVideoUrl = $request->containsVideoUploads();
155
        $url = $this->getBaseGraphUrl($postToVideoUrl) . $request->getUrl();
156
157
        // If we're sending files they should be sent as multipart/form-data
158
        if ($request->containsFileUploads()) {
159
            $requestBody = $request->getMultipartBody();
160
            $request->setHeaders([
161
                'Content-Type' => 'multipart/form-data; boundary=' . $requestBody->getBoundary(),
162
            ]);
163
        } else {
164
            $requestBody = $request->getUrlEncodedBody();
165
            $request->setHeaders([
166
                'Content-Type' => 'application/x-www-form-urlencoded',
167
            ]);
168
        }
169
170
        return [
171
            $url,
172
            $request->getMethod(),
173
            $request->getHeaders(),
174
            $requestBody->getBody(),
175
        ];
176
    }
177
178
    /**
179
     * Makes the request to Graph and returns the result.
180
     *
181
     * @param Request $request
182
     *
183
     * @return Response
184
     *
185
     * @throws SDKException
186
     */
187
    public function sendRequest(Request $request)
188
    {
189
        if (get_class($request) === 'Facebook\Request') {
190
            $request->validateAccessToken();
191
        }
192
193
        list($url, $method, $headers, $body) = $this->prepareRequestMessage($request);
194
195
        $psr7Response = $this->httpClient->sendRequest(
196
            MessageFactoryDiscovery::find()->createRequest($method, $url, $headers, $body)
197
        );
198
199
        static::$requestCount++;
200
201
        // Prepare headers from associative array to a single string for each header.
202
        $responseHeaders = [];
203
        foreach ($psr7Response->getHeaders() as $name => $values) {
204
            $responseHeaders[] = sprintf('%s: %s', $name, implode(", ", $values));
205
        }
206
207
        $facebookResponse = new Response(
208
            $request,
209
            $psr7Response->getBody(),
210
            $psr7Response->getStatusCode(),
211
            $responseHeaders
212
        );
213
214
        if ($facebookResponse->isError()) {
215
            throw $facebookResponse->getThrownException();
216
        }
217
218
        return $facebookResponse;
219
    }
220
221
    /**
222
     * Makes a batched request to Graph and returns the result.
223
     *
224
     * @param BatchRequest $request
225
     *
226
     * @return BatchResponse
227
     *
228
     * @throws SDKException
229
     */
230
    public function sendBatchRequest(BatchRequest $request)
231
    {
232
        $request->prepareRequestsForBatch();
233
        $facebookResponse = $this->sendRequest($request);
234
235
        return new BatchResponse($request, $facebookResponse);
236
    }
237
}
238