Failed Conditions
Pull Request — master (#1145)
by
unknown
03:10
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\ClientInterface;
27
use Psr\Http\Message\MessageInterface;
28
use Psr\Http\Message\RequestFactoryInterface;
29
use Psr\Http\Message\RequestInterface;
30
use Psr\Http\Message\StreamFactoryInterface;
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 ClientInterface HTTP client handler
79
     */
80
    protected $httpClient;
81
82
    /**
83
     * @var RequestFactoryInterface
84
     */
85
    private $requestFactory;
86
87
    /**
88
     * @var StreamFactoryInterface
89
     */
90
    private $streamFactory;
91
92
    /**
93
     * @var int the number of calls that have been made to Graph
94
     */
95
    public static $requestCount = 0;
96
97
    /**
98
     * Instantiates a new Client object.
99
     *
100
     * @param ClientInterface $httpClient
101
     * @param RequestFactoryInterface $requestFactory
102
     * @param StreamFactoryInterface  $streamFactory
103
     * @param bool            $enableBeta
104
     */
105 41
    public function __construct(
106
        ClientInterface $httpClient,
107
        RequestFactoryInterface $requestFactory,
108
        StreamFactoryInterface $streamFactory,
109
        $enableBeta = false
110
    ) {
111 41
        $this->httpClient = $httpClient;
112 41
        $this->enableBetaMode = $enableBeta;
113 41
        $this->requestFactory = $requestFactory;
114 41
        $this->streamFactory = $streamFactory;
115 41
    }
116
117
    /**
118
     * Sets the HTTP client handler.
119
     *
120
     * @param ClientInterface $httpClient
121
     */
122
    public function setHttpClient(ClientInterface $httpClient)
123
    {
124
        $this->httpClient = $httpClient;
125
    }
126
127
    /**
128
     * Returns the HTTP client handler.
129
     *
130
     * @return ClientInterface
131
     */
132 2
    public function getHttpClient()
133
    {
134 2
        return $this->httpClient;
135
    }
136
137
    /**
138
     * Toggle beta mode.
139
     *
140
     * @param bool $betaMode
141
     */
142 2
    public function enableBetaMode($betaMode = true)
143
    {
144 2
        $this->enableBetaMode = $betaMode;
145 2
    }
146
147
    /**
148
     * Returns the base Graph URL.
149
     *
150
     * @param bool $postToVideoUrl post to the video API if videos are being uploaded
151
     *
152
     * @return string
153
     */
154 15
    public function getBaseGraphUrl($postToVideoUrl = false)
155
    {
156 15
        if ($postToVideoUrl) {
157 2
            return $this->enableBetaMode ? static::BASE_GRAPH_VIDEO_URL_BETA : static::BASE_GRAPH_VIDEO_URL;
158
        }
159
160 13
        return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL;
161
    }
162
163
    /**
164
     * Prepares the request for sending to the client handler.
165
     * @deprecated
166
     *
167
     * @param Request $request
168
     *
169
     * @return array
170
     */
171 1
    public function prepareRequestMessage(Request $request)
172
    {
173 1
        $postToVideoUrl = $request->containsVideoUploads();
174 1
        $url = $this->getBaseGraphUrl($postToVideoUrl) . $request->getUrl();
175
176
        // If we're sending files they should be sent as multipart/form-data
177 1
        if ($request->containsFileUploads()) {
178 1
            $requestBody = $request->getMultipartBody();
179 1
            $request->setHeaders([
180 1
                'Content-Type' => 'multipart/form-data; boundary=' . $requestBody->getBoundary(),
181
            ]);
182
        } else {
183
            $requestBody = $request->getUrlEncodedBody();
184
            $request->setHeaders([
185
                'Content-Type' => 'application/x-www-form-urlencoded',
186
            ]);
187
        }
188
189
        return [
190 1
            $url,
191 1
            $request->getMethod(),
192 1
            $request->getHeaders(),
193 1
            $requestBody->getBody(),
194
        ];
195
    }
196
197
    /**
198
     * Makes the request to Graph and returns the result.
199
     *
200
     * @param Request $request
201
     *
202
     * @throws SDKException
203
     *
204
     * @return Response
205
     */
206 10
    public function sendRequest(Request $request)
207
    {
208 10
        if (get_class($request) === 'Facebook\Request') {
209 9
            $request->validateAccessToken();
210
        }
211
212 9
        $psr7Request = $this->createPSR7RequestFromFacebookRequest($request);
213
        // Add headers to FacebookRequest
214 9
        $request->setHeaders($this->flattenPSR7Headers($psr7Request, $psr7Request->getHeaders()));
215
216 9
        $psr7Response = $this->httpClient->sendRequest($psr7Request);
217
218 9
        static::$requestCount++;
219
220
        // Prepare headers from associative array to a single string for each header.
221 9
        $responseHeaders = $this->flattenPSR7Headers($psr7Response);
222
223 9
        $Response = new Response(
224 9
            $request,
225 9
            $psr7Response->getBody(),
226 9
            $psr7Response->getStatusCode(),
227 9
            $responseHeaders
228
        );
229
230 9
        if ($Response->isError()) {
231 3
            throw $Response->getThrownException();
232
        }
233
234 7
        return $Response;
235
    }
236
237
    /**
238
     * Makes a batched request to Graph and returns the result.
239
     *
240
     * @param BatchRequest $request
241
     *
242
     * @throws SDKException
243
     *
244
     * @return BatchResponse
245
     */
246 1
    public function sendBatchRequest(BatchRequest $request)
247
    {
248 1
        $request->prepareRequestsForBatch();
249 1
        $Response = $this->sendRequest($request);
250
251 1
        return new BatchResponse($request, $Response);
252
    }
253
254 9
    private function createPSR7RequestFromFacebookRequest(Request $facebookRequest): RequestInterface
255
    {
256 9
        $postToVideoUrl = $facebookRequest->containsVideoUploads();
257 9
        $uri = $this->getBaseGraphUrl($postToVideoUrl) . $facebookRequest->getUrl();
258
259 9
        $psrRequest = $this->requestFactory->createRequest($facebookRequest->getMethod(), $uri);
260
261
        // If we're sending files they should be sent as multipart/form-data
262 9
        if ($facebookRequest->containsFileUploads()) {
263 5
            $requestBody = $facebookRequest->getMultipartBody();
264 5
            $psrRequest = $psrRequest->withHeader(
265 5
                'Content-Type',
266 5
                'multipart/form-data; boundary=' . $requestBody->getBoundary()
267
            );
268
        } else {
269 7
            $requestBody = $facebookRequest->getUrlEncodedBody();
270 7
            $psrRequest = $psrRequest->withHeader('Content-Type', 'application/x-www-form-urlencoded');
271
        }
272
273
        // Create a StreamInterface from request body.
274 9
        $bodyStream = $this->streamFactory->createStream($requestBody->getBody());
275
276 9
        return $psrRequest->withBody($bodyStream);
277
    }
278
279 9
    private function flattenPSR7Headers(MessageInterface $psr7Message, array $initialValues = []): array
280
    {
281 9
        $flattenedHeaders = array_map(
282
            function ($value) { return implode(', ', $value); },
0 ignored issues
show
Opening brace must be the last content on the line
Loading history...
283 9
            $psr7Message->getHeaders()
284
        );
285
        /* Old Implementation taken from sendRequest()
286
        foreach ($psr7Message->getHeaders() as $name => $values) {
287
            $initialValues[$name] = implode(", ", $values);
288
        }*/
289 9
        return array_merge($initialValues, $flattenedHeaders);
290
    }
291
}
292