Failed Conditions
Pull Request — master (#1145)
by
unknown
01:50
created

src/Client.php (1 issue)

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
namespace Facebook;
24
25
use Facebook\Exception\SDKException;
26
use Psr\Http\Client\ClientExceptionInterface;
27
use Psr\Http\Client\ClientInterface;
28
use Psr\Http\Message\MessageInterface;
29
use Psr\Http\Message\RequestFactoryInterface;
30
use Psr\Http\Message\RequestInterface;
31
use Psr\Http\Message\StreamFactoryInterface;
32
33
/**
34
 * @package Facebook
35
 */
36
class Client
37
{
38
    /**
39
     * @const string Production Graph API URL.
40
     */
41
    const BASE_GRAPH_URL = 'https://graph.facebook.com';
42
43
    /**
44
     * @const string Graph API URL for video uploads.
45
     */
46
    const BASE_GRAPH_VIDEO_URL = 'https://graph-video.facebook.com';
47
48
    /**
49
     * @const string Beta Graph API URL.
50
     */
51
    const BASE_GRAPH_URL_BETA = 'https://graph.beta.facebook.com';
52
53
    /**
54
     * @const string Beta Graph API URL for video uploads.
55
     */
56
    const BASE_GRAPH_VIDEO_URL_BETA = 'https://graph-video.beta.facebook.com';
57
58
    /**
59
     * @const int The timeout in seconds for a normal request.
60
     */
61
    const DEFAULT_REQUEST_TIMEOUT = 60;
62
63
    /**
64
     * @const int The timeout in seconds for a request that contains file uploads.
65
     */
66
    const DEFAULT_FILE_UPLOAD_REQUEST_TIMEOUT = 3600;
67
68
    /**
69
     * @const int The timeout in seconds for a request that contains video uploads.
70
     */
71
    const DEFAULT_VIDEO_UPLOAD_REQUEST_TIMEOUT = 7200;
72
73
    /**
74
     * @var bool toggle to use Graph beta url
75
     */
76
    protected $enableBetaMode = false;
77
78
    /**
79
     * @var ClientInterface HTTP client handler
80
     */
81
    protected $httpClient;
82
83
    /**
84
     * @var RequestFactoryInterface
85
     */
86
    private $requestFactory;
87
88
    /**
89
     * @var StreamFactoryInterface
90
     */
91
    private $streamFactory;
92
93
    /**
94
     * @var int the number of calls that have been made to Graph
95
     */
96
    public static $requestCount = 0;
97
98
    /**
99
     * Instantiates a new Client object.
100
     *
101
     * @param ClientInterface $httpClient
102
     * @param RequestFactoryInterface $requestFactory
103
     * @param StreamFactoryInterface  $streamFactory
104
     * @param bool            $enableBeta
105
     */
106 41
    public function __construct(
107
        ClientInterface $httpClient,
108
        RequestFactoryInterface $requestFactory,
109
        StreamFactoryInterface $streamFactory,
110
        $enableBeta = false
111
    ) {
112 41
        $this->httpClient = $httpClient;
113 41
        $this->enableBetaMode = $enableBeta;
114 41
        $this->requestFactory = $requestFactory;
115 41
        $this->streamFactory = $streamFactory;
116 41
    }
117
118
    /**
119
     * Sets the HTTP client handler.
120
     *
121
     * @param ClientInterface $httpClient
122
     */
123
    public function setHttpClient(ClientInterface $httpClient)
124
    {
125
        $this->httpClient = $httpClient;
126
    }
127
128
    /**
129
     * Returns the HTTP client handler.
130
     *
131
     * @return ClientInterface
132
     */
133 2
    public function getHttpClient()
134
    {
135 2
        return $this->httpClient;
136
    }
137
138
    /**
139
     * Toggle beta mode.
140
     *
141
     * @param bool $betaMode
142
     */
143 2
    public function enableBetaMode($betaMode = true)
144
    {
145 2
        $this->enableBetaMode = $betaMode;
146 2
    }
147
148
    /**
149
     * Returns the base Graph URL.
150
     *
151
     * @param bool $postToVideoUrl post to the video API if videos are being uploaded
152
     *
153
     * @return string
154
     */
155 15
    public function getBaseGraphUrl($postToVideoUrl = false)
156
    {
157 15
        if ($postToVideoUrl) {
158 2
            return $this->enableBetaMode ? static::BASE_GRAPH_VIDEO_URL_BETA : static::BASE_GRAPH_VIDEO_URL;
159
        }
160
161 13
        return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL;
162
    }
163
164
    /**
165
     * Prepares the request for sending to the client handler.
166
     * @deprecated
167
     *
168
     * @param Request $request
169
     *
170
     * @return array
171
     */
172 1
    public function prepareRequestMessage(Request $request)
173
    {
174 1
        $postToVideoUrl = $request->containsVideoUploads();
175 1
        $url = $this->getBaseGraphUrl($postToVideoUrl) . $request->getUrl();
176
177
        // If we're sending files they should be sent as multipart/form-data
178 1
        if ($request->containsFileUploads()) {
179 1
            $requestBody = $request->getMultipartBody();
180 1
            $request->setHeaders([
181 1
                'Content-Type' => 'multipart/form-data; boundary=' . $requestBody->getBoundary(),
182
            ]);
183
        } else {
184
            $requestBody = $request->getUrlEncodedBody();
185
            $request->setHeaders([
186
                'Content-Type' => 'application/x-www-form-urlencoded',
187
            ]);
188
        }
189
190
        return [
191 1
            $url,
192 1
            $request->getMethod(),
193 1
            $request->getHeaders(),
194 1
            $requestBody->getBody(),
195
        ];
196
    }
197
198
    /**
199
     * Makes the request to Graph and returns the result.
200
     *
201
     * @param Request $request
202
     *
203
     * @return Response
204
     * @throws ClientExceptionInterface
205
     *
206
     * @throws SDKException
207
     */
208 10
    public function sendRequest(Request $request)
209
    {
210 10
        if (get_class($request) === 'Facebook\Request') {
211 9
            $request->validateAccessToken();
212
        }
213
214 9
        $psr7Request = $this->createPSR7RequestFromFacebookRequest($request);
215
        // Add headers to FacebookRequest
216 9
        $request->setHeaders($this->flattenPSR7Headers($psr7Request, $psr7Request->getHeaders()));
217
218 9
        $psr7Response = $this->httpClient->sendRequest($psr7Request);
219
220 9
        static::$requestCount++;
221
222
        // Prepare headers from associative array to a single string for each header.
223 9
        $responseHeaders = $this->flattenPSR7Headers($psr7Response);
224
225 9
        $Response = new Response(
226 9
            $request,
227 9
            $psr7Response->getBody(),
228 9
            $psr7Response->getStatusCode(),
229 9
            $responseHeaders
230
        );
231
232 9
        if ($Response->isError()) {
233 3
            throw $Response->getThrownException();
234
        }
235
236 7
        return $Response;
237
    }
238
239
    /**
240
     * Makes a batched request to Graph and returns the result.
241
     *
242
     * @param BatchRequest $request
243
     *
244
     * @return BatchResponse
245
     * @throws ClientExceptionInterface
246
     *
247
     * @throws SDKException
248
     */
249 1
    public function sendBatchRequest(BatchRequest $request)
250
    {
251 1
        $request->prepareRequestsForBatch();
252 1
        $Response = $this->sendRequest($request);
253
254 1
        return new BatchResponse($request, $Response);
255
    }
256
257
    /**
258
     * @TODO Move this to the Facebook\Request class
259
     * Create and prepares a PSR-7 object from a Facebook\Request object to be used with a PSR-18 Client
260
     * @param Request $facebookRequest
261
     * @return RequestInterface
262
     */
263 9
    private function createPSR7RequestFromFacebookRequest(Request $facebookRequest): RequestInterface
264
    {
265 9
        $postToVideoUrl = $facebookRequest->containsVideoUploads();
266 9
        $uri = $this->getBaseGraphUrl($postToVideoUrl) . $facebookRequest->getUrl();
267
268 9
        $psrRequest = $this->requestFactory->createRequest($facebookRequest->getMethod(), $uri);
269
270
        // If we're sending files they should be sent as multipart/form-data
271 9
        if ($facebookRequest->containsFileUploads()) {
272 5
            $requestBody = $facebookRequest->getMultipartBody();
273 5
            $psrRequest = $psrRequest->withHeader(
274 5
                'Content-Type',
275 5
                'multipart/form-data; boundary=' . $requestBody->getBoundary()
276
            );
277
        } else {
278 7
            $requestBody = $facebookRequest->getUrlEncodedBody();
279 7
            $psrRequest = $psrRequest->withHeader('Content-Type', 'application/x-www-form-urlencoded');
280
        }
281
282
        // Create a StreamInterface from request body.
283 9
        $bodyStream = $this->streamFactory->createStream($requestBody->getBody());
284
285 9
        return $psrRequest->withBody($bodyStream);
286
    }
287
288
    /**
289
     * Flatten PSR-7 headers such they can be added to a Facebook\Response|Facebook\Request
290
     * @param MessageInterface $psr7Message
291
     * @param array $initialValues
292
     * @return array
293
     */
294 9
    private function flattenPSR7Headers(MessageInterface $psr7Message, array $initialValues = []): array
295
    {
296 9
        $flattenedHeaders = array_map(
297
            function ($value) { return implode(', ', $value); },
0 ignored issues
show
Opening brace must be the last content on the line
Loading history...
298 9
            $psr7Message->getHeaders()
299
        );
300 9
        return array_merge($initialValues, $flattenedHeaders);
301
    }
302
}
303