Failed Conditions
Pull Request — master (#1145)
by
unknown
02: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\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
    private $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 40
    public function __construct(
107
        ClientInterface $httpClient,
108
        RequestFactoryInterface $requestFactory,
109
        StreamFactoryInterface $streamFactory,
110
        $enableBeta = false
111
    ) {
112 40
        $this->httpClient = $httpClient;
113 40
        $this->enableBetaMode = $enableBeta;
114 40
        $this->requestFactory = $requestFactory;
115 40
        $this->streamFactory = $streamFactory;
116 40
    }
117
118
    /**
119
     * Toggle beta mode.
120
     *
121
     * @param bool $betaMode
122
     */
123 2
    public function enableBetaMode($betaMode = true)
124
    {
125 2
        $this->enableBetaMode = $betaMode;
126 2
    }
127
128
    /**
129
     * Returns the base Graph URL.
130
     *
131
     * @param bool $postToVideoUrl post to the video API if videos are being uploaded
132
     *
133
     * @return string
134
     */
135 15
    public function getBaseGraphUrl($postToVideoUrl = false)
136
    {
137 15
        if ($postToVideoUrl) {
138 2
            return $this->enableBetaMode ? static::BASE_GRAPH_VIDEO_URL_BETA : static::BASE_GRAPH_VIDEO_URL;
139
        }
140
141 13
        return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL;
142
    }
143
144
    /**
145
     * Prepares the request for sending to the client handler.
146
     * @deprecated
147
     *
148
     * @param Request $request
149
     *
150
     * @return array
151
     */
152 1
    public function prepareRequestMessage(Request $request)
153
    {
154 1
        $postToVideoUrl = $request->containsVideoUploads();
155 1
        $url = $this->getBaseGraphUrl($postToVideoUrl) . $request->getUrl();
156
157
        // If we're sending files they should be sent as multipart/form-data
158 1
        if ($request->containsFileUploads()) {
159 1
            $requestBody = $request->getMultipartBody();
160 1
            $request->setHeaders([
161 1
                '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 1
            $url,
172 1
            $request->getMethod(),
173 1
            $request->getHeaders(),
174 1
            $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
     * @throws ClientExceptionInterface
185
     *
186
     * @throws SDKException
187
     */
188 10
    public function sendRequest(Request $request)
189
    {
190 10
        if (get_class($request) === 'Facebook\Request') {
191 9
            $request->validateAccessToken();
192
        }
193
194 9
        $psr7Request = $this->createPSR7RequestFromFacebookRequest($request);
195
        // Add headers to FacebookRequest
196 9
        $request->setHeaders($this->flattenPSR7Headers($psr7Request, $psr7Request->getHeaders()));
197
198 9
        $psr7Response = $this->httpClient->sendRequest($psr7Request);
199
200 9
        static::$requestCount++;
201
202
        // Prepare headers from associative array to a single string for each header.
203 9
        $responseHeaders = $this->flattenPSR7Headers($psr7Response);
204
205 9
        $Response = new Response(
206 9
            $request,
207 9
            $psr7Response->getBody(),
208 9
            $psr7Response->getStatusCode(),
209 9
            $responseHeaders
210
        );
211
212 9
        if ($Response->isError()) {
213 3
            throw $Response->getThrownException();
214
        }
215
216 7
        return $Response;
217
    }
218
219
    /**
220
     * Makes a batched request to Graph and returns the result.
221
     *
222
     * @param BatchRequest $request
223
     *
224
     * @return BatchResponse
225
     * @throws ClientExceptionInterface
226
     *
227
     * @throws SDKException
228
     */
229 1
    public function sendBatchRequest(BatchRequest $request)
230
    {
231 1
        $request->prepareRequestsForBatch();
232 1
        $Response = $this->sendRequest($request);
233
234 1
        return new BatchResponse($request, $Response);
235
    }
236
237
    /**
238
     * @TODO Move this to the Facebook\Request class
239
     * Create and prepares a PSR-7 object from a Facebook\Request object to be used with a PSR-18 Client
240
     * @param Request $facebookRequest
241
     * @return RequestInterface
242
     */
243 9
    private function createPSR7RequestFromFacebookRequest(Request $facebookRequest): RequestInterface
244
    {
245 9
        $postToVideoUrl = $facebookRequest->containsVideoUploads();
246 9
        $uri = $this->getBaseGraphUrl($postToVideoUrl) . $facebookRequest->getUrl();
247
248 9
        $psrRequest = $this->requestFactory->createRequest($facebookRequest->getMethod(), $uri);
249
250
        // If we're sending files they should be sent as multipart/form-data
251 9
        if ($facebookRequest->containsFileUploads()) {
252 5
            $requestBody = $facebookRequest->getMultipartBody();
253 5
            $psrRequest = $psrRequest->withHeader(
254 5
                'Content-Type',
255 5
                'multipart/form-data; boundary=' . $requestBody->getBoundary()
256
            );
257
        } else {
258 7
            $requestBody = $facebookRequest->getUrlEncodedBody();
259 7
            $psrRequest = $psrRequest->withHeader('Content-Type', 'application/x-www-form-urlencoded');
260
        }
261
262
        // Create a StreamInterface from request body.
263 9
        $bodyStream = $this->streamFactory->createStream($requestBody->getBody());
264
265 9
        return $psrRequest->withBody($bodyStream);
266
    }
267
268
    /**
269
     * Flatten PSR-7 headers such they can be added to a Facebook\Response|Facebook\Request
270
     * @param MessageInterface $psr7Message
271
     * @param array $initialValues
272
     * @return array
273
     */
274 9
    private function flattenPSR7Headers(MessageInterface $psr7Message, array $initialValues = []): array
275
    {
276 9
        $flattenedHeaders = array_map(
277
            function ($value) { return implode(', ', $value); },
0 ignored issues
show
Opening brace must be the last content on the line
Loading history...
278 9
            $psr7Message->getHeaders()
279
        );
280 9
        return array_merge($initialValues, $flattenedHeaders);
281
    }
282
}
283