Passed
Pull Request — 5.x (#953)
by
unknown
01:47
created

Facebook   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 583
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 583
rs 8.5454
c 0
b 0
f 0
wmc 49

How to fix   Complexity   

Complex Class

Complex classes like Facebook often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Facebook, and based on these observations, apply Extract Interface, too.

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\Authentication\AccessToken;
27
use Facebook\Authentication\OAuth2Client;
28
use Facebook\FileUpload\FacebookFile;
29
use Facebook\FileUpload\FacebookResumableUploader;
30
use Facebook\FileUpload\FacebookTransferChunk;
31
use Facebook\FileUpload\FacebookVideo;
32
use Facebook\GraphNodes\GraphEdge;
33
use Facebook\Url\UrlDetectionInterface;
34
use Facebook\Url\FacebookUrlDetectionHandler;
35
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorFactory;
36
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface;
37
use Facebook\HttpClients\HttpClientsFactory;
38
use Facebook\PersistentData\PersistentDataFactory;
39
use Facebook\PersistentData\PersistentDataInterface;
40
use Facebook\Helpers\FacebookCanvasHelper;
41
use Facebook\Helpers\FacebookJavaScriptHelper;
42
use Facebook\Helpers\FacebookPageTabHelper;
43
use Facebook\Helpers\FacebookRedirectLoginHelper;
44
use Facebook\Exceptions\FacebookSDKException;
45
46
/**
47
 * Class Facebook
48
 *
49
 * @package Facebook
50
 */
51
class Facebook
52
{
53
    /**
54
     * @const string Version number of the Facebook PHP SDK.
55
     */
56
    const VERSION = '5.6.2';
57
58
    /**
59
     * @const string Default Graph API version for requests.
60
     */
61
    const DEFAULT_GRAPH_VERSION = 'v2.10';
62
63
    /**
64
     * @const string The name of the environment variable that contains the app ID.
65
     */
66
    const APP_ID_ENV_NAME = 'FACEBOOK_APP_ID';
67
68
    /**
69
     * @const string The name of the environment variable that contains the app secret.
70
     */
71
    const APP_SECRET_ENV_NAME = 'FACEBOOK_APP_SECRET';
72
73
    /**
74
     * @var FacebookApp The FacebookApp entity.
75
     */
76
    protected $app;
77
78
    /**
79
     * @var FacebookClient The Facebook client service.
80
     */
81
    protected $client;
82
83
    /**
84
     * @var OAuth2Client The OAuth 2.0 client service.
85
     */
86
    protected $oAuth2Client;
87
88
    /**
89
     * @var UrlDetectionInterface|null The URL detection handler.
90
     */
91
    protected $urlDetectionHandler;
92
93
    /**
94
     * @var PseudoRandomStringGeneratorInterface|null The cryptographically secure pseudo-random string generator.
95
     */
96
    protected $pseudoRandomStringGenerator;
97
98
    /**
99
     * @var AccessToken|null The default access token to use with requests.
100
     */
101
    protected $defaultAccessToken;
102
103
    /**
104
     * @var string|null The default Graph version we want to use.
105
     */
106
    protected $defaultGraphVersion;
107
108
    /**
109
     * @var PersistentDataInterface|null The persistent data handler.
110
     */
111
    protected $persistentDataHandler;
112
113
    /**
114
     * @var FacebookResponse|FacebookBatchResponse|null Stores the last request made to Graph.
115
     */
116
    protected $lastResponse;
117
118
    /**
119
     * Instantiates a new Facebook super-class object.
120
     *
121
     * @param array $config
122
     *
123
     * @throws FacebookSDKException
124
     */
125
    public function __construct(array $config = [])
126
    {
127
        $config = array_merge([
128
            'app_id' => getenv(static::APP_ID_ENV_NAME),
129
            'app_secret' => getenv(static::APP_SECRET_ENV_NAME),
130
            'default_graph_version' => static::DEFAULT_GRAPH_VERSION,
131
            'enable_beta_mode' => false,
132
            'http_client_handler' => null,
133
            'persistent_data_handler' => null,
134
            'pseudo_random_string_generator' => null,
135
            'url_detection_handler' => null,
136
        ], $config);
137
138
        if (!$config['app_id']) {
139
            throw new FacebookSDKException('Required "app_id" key not supplied in config and could not find fallback environment variable "' . static::APP_ID_ENV_NAME . '"');
140
        }
141
        if (!$config['app_secret']) {
142
            throw new FacebookSDKException('Required "app_secret" key not supplied in config and could not find fallback environment variable "' . static::APP_SECRET_ENV_NAME . '"');
143
        }
144
145
        $this->app = new FacebookApp($config['app_id'], $config['app_secret']);
146
        $this->client = new FacebookClient(
147
            HttpClientsFactory::createHttpClient($config['http_client_handler']),
148
            $config['enable_beta_mode']
149
        );
150
        $this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator(
151
            $config['pseudo_random_string_generator']
152
        );
153
        $this->setUrlDetectionHandler($config['url_detection_handler'] ?: new FacebookUrlDetectionHandler());
154
        $this->persistentDataHandler = PersistentDataFactory::createPersistentDataHandler(
155
            $config['persistent_data_handler']
156
        );
157
158
        if (isset($config['default_access_token'])) {
159
            $this->setDefaultAccessToken($config['default_access_token']);
160
        }
161
162
        // @todo v6: Throw an InvalidArgumentException if "default_graph_version" is not set
163
        $this->defaultGraphVersion = $config['default_graph_version'];
164
    }
165
166
    /**
167
     * Returns the FacebookApp entity.
168
     *
169
     * @return FacebookApp
170
     */
171
    public function getApp()
172
    {
173
        return $this->app;
174
    }
175
176
    /**
177
     * Returns the FacebookClient service.
178
     *
179
     * @return FacebookClient
180
     */
181
    public function getClient()
182
    {
183
        return $this->client;
184
    }
185
186
    /**
187
     * Returns the OAuth 2.0 client service.
188
     *
189
     * @return OAuth2Client
190
     */
191
    public function getOAuth2Client()
192
    {
193
        if (!$this->oAuth2Client instanceof OAuth2Client) {
194
            $app = $this->getApp();
195
            $client = $this->getClient();
196
            $this->oAuth2Client = new OAuth2Client($app, $client, $this->defaultGraphVersion);
197
        }
198
199
        return $this->oAuth2Client;
200
    }
201
202
    /**
203
     * Returns the last response returned from Graph.
204
     *
205
     * @return FacebookResponse|FacebookBatchResponse|null
206
     */
207
    public function getLastResponse()
208
    {
209
        return $this->lastResponse;
210
    }
211
212
    /**
213
     * Returns the URL detection handler.
214
     *
215
     * @return UrlDetectionInterface
216
     */
217
    public function getUrlDetectionHandler()
218
    {
219
        return $this->urlDetectionHandler;
220
    }
221
222
    /**
223
     * Changes the URL detection handler.
224
     *
225
     * @param UrlDetectionInterface $urlDetectionHandler
226
     */
227
    private function setUrlDetectionHandler(UrlDetectionInterface $urlDetectionHandler)
228
    {
229
        $this->urlDetectionHandler = $urlDetectionHandler;
230
    }
231
232
    /**
233
     * Returns the default AccessToken entity.
234
     *
235
     * @return AccessToken|null
236
     */
237
    public function getDefaultAccessToken()
238
    {
239
        return $this->defaultAccessToken;
240
    }
241
242
    /**
243
     * Sets the default access token to use with requests.
244
     *
245
     * @param AccessToken|string $accessToken The access token to save.
246
     *
247
     * @throws \InvalidArgumentException
248
     */
249
    public function setDefaultAccessToken($accessToken)
250
    {
251
        if (is_string($accessToken)||$accessToken instanceof AccessToken) {
252
            if(is_string($accessToken){
253
                $this->defaultAccessToken = new AccessToken($accessToken);
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected ';' on line 253 at column 73
Loading history...
254
            }elseif($accessToken instanceof AccessToken) {
255
                $this->defaultAccessToken = $accessToken;
256
            }
257
            return;
258
        }
259
260
        throw new \InvalidArgumentException('The default access token must be of type "string" or Facebook\AccessToken');
261
    }
262
263
    /**
264
     * Returns the default Graph version.
265
     *
266
     * @return string
267
     */
268
    public function getDefaultGraphVersion()
269
    {
270
        return $this->defaultGraphVersion;
271
    }
272
273
    /**
274
     * Returns the redirect login helper.
275
     *
276
     * @return FacebookRedirectLoginHelper
277
     */
278
    public function getRedirectLoginHelper()
279
    {
280
        return new FacebookRedirectLoginHelper(
281
            $this->getOAuth2Client(),
282
            $this->persistentDataHandler,
283
            $this->urlDetectionHandler,
284
            $this->pseudoRandomStringGenerator
285
        );
286
    }
287
288
    /**
289
     * Returns the JavaScript helper.
290
     *
291
     * @return FacebookJavaScriptHelper
292
     */
293
    public function getJavaScriptHelper()
294
    {
295
        return new FacebookJavaScriptHelper($this->app, $this->client, $this->defaultGraphVersion);
296
    }
297
298
    /**
299
     * Returns the canvas helper.
300
     *
301
     * @return FacebookCanvasHelper
302
     */
303
    public function getCanvasHelper()
304
    {
305
        return new FacebookCanvasHelper($this->app, $this->client, $this->defaultGraphVersion);
306
    }
307
308
    /**
309
     * Returns the page tab helper.
310
     *
311
     * @return FacebookPageTabHelper
312
     */
313
    public function getPageTabHelper()
314
    {
315
        return new FacebookPageTabHelper($this->app, $this->client, $this->defaultGraphVersion);
316
    }
317
318
    /**
319
     * Sends a GET request to Graph and returns the result.
320
     *
321
     * @param string                  $endpoint
322
     * @param AccessToken|string|null $accessToken
323
     * @param string|null             $eTag
324
     * @param string|null             $graphVersion
325
     *
326
     * @return FacebookResponse
327
     *
328
     * @throws FacebookSDKException
329
     */
330
    public function get($endpoint, $accessToken = null, $eTag = null, $graphVersion = null)
331
    {
332
        return $this->sendRequest(
333
            'GET',
334
            $endpoint,
335
            $params = [],
336
            $accessToken,
337
            $eTag,
338
            $graphVersion
339
        );
340
    }
341
342
    /**
343
     * Sends a POST request to Graph and returns the result.
344
     *
345
     * @param string                  $endpoint
346
     * @param array                   $params
347
     * @param AccessToken|string|null $accessToken
348
     * @param string|null             $eTag
349
     * @param string|null             $graphVersion
350
     *
351
     * @return FacebookResponse
352
     *
353
     * @throws FacebookSDKException
354
     */
355
    public function post($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
356
    {
357
        return $this->sendRequest(
358
            'POST',
359
            $endpoint,
360
            $params,
361
            $accessToken,
362
            $eTag,
363
            $graphVersion
364
        );
365
    }
366
367
    /**
368
     * Sends a DELETE request to Graph and returns the result.
369
     *
370
     * @param string                  $endpoint
371
     * @param array                   $params
372
     * @param AccessToken|string|null $accessToken
373
     * @param string|null             $eTag
374
     * @param string|null             $graphVersion
375
     *
376
     * @return FacebookResponse
377
     *
378
     * @throws FacebookSDKException
379
     */
380
    public function delete($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
381
    {
382
        return $this->sendRequest(
383
            'DELETE',
384
            $endpoint,
385
            $params,
386
            $accessToken,
387
            $eTag,
388
            $graphVersion
389
        );
390
    }
391
392
    /**
393
     * Sends a request to Graph for the next page of results.
394
     *
395
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
396
     *
397
     * @return GraphEdge|null
398
     *
399
     * @throws FacebookSDKException
400
     */
401
    public function next(GraphEdge $graphEdge)
402
    {
403
        return $this->getPaginationResults($graphEdge, 'next');
404
    }
405
406
    /**
407
     * Sends a request to Graph for the previous page of results.
408
     *
409
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
410
     *
411
     * @return GraphEdge|null
412
     *
413
     * @throws FacebookSDKException
414
     */
415
    public function previous(GraphEdge $graphEdge)
416
    {
417
        return $this->getPaginationResults($graphEdge, 'previous');
418
    }
419
420
    /**
421
     * Sends a request to Graph for the next page of results.
422
     *
423
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
424
     * @param string    $direction The direction of the pagination: next|previous.
425
     *
426
     * @return GraphEdge|null
427
     *
428
     * @throws FacebookSDKException
429
     */
430
    public function getPaginationResults(GraphEdge $graphEdge, $direction)
431
    {
432
        $paginationRequest = $graphEdge->getPaginationRequest($direction);
433
        if (!$paginationRequest) {
434
            return null;
435
        }
436
437
        $this->lastResponse = $this->client->sendRequest($paginationRequest);
438
439
        // Keep the same GraphNode subclass
440
        $subClassName = $graphEdge->getSubClassName();
441
        $graphEdge = $this->lastResponse->getGraphEdge($subClassName, false);
442
443
        return count($graphEdge) > 0 ? $graphEdge : null;
444
    }
445
446
    /**
447
     * Sends a request to Graph and returns the result.
448
     *
449
     * @param string                  $method
450
     * @param string                  $endpoint
451
     * @param array                   $params
452
     * @param AccessToken|string|null $accessToken
453
     * @param string|null             $eTag
454
     * @param string|null             $graphVersion
455
     *
456
     * @return FacebookResponse
457
     *
458
     * @throws FacebookSDKException
459
     */
460
    public function sendRequest($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
461
    {
462
        $accessToken = $accessToken ?: $this->defaultAccessToken;
463
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
464
        $request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion);
465
466
        return $this->lastResponse = $this->client->sendRequest($request);
467
    }
468
469
    /**
470
     * Sends a batched request to Graph and returns the result.
471
     *
472
     * @param array                   $requests
473
     * @param AccessToken|string|null $accessToken
474
     * @param string|null             $graphVersion
475
     *
476
     * @return FacebookBatchResponse
477
     *
478
     * @throws FacebookSDKException
479
     */
480
    public function sendBatchRequest(array $requests, $accessToken = null, $graphVersion = null)
481
    {
482
        $accessToken = $accessToken ?: $this->defaultAccessToken;
483
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
484
        $batchRequest = new FacebookBatchRequest(
485
            $this->app,
486
            $requests,
487
            $accessToken,
488
            $graphVersion
489
        );
490
491
        return $this->lastResponse = $this->client->sendBatchRequest($batchRequest);
492
    }
493
494
    /**
495
     * Instantiates an empty FacebookBatchRequest entity.
496
     *
497
     * @param  AccessToken|string|null $accessToken  The top-level access token. Requests with no access token
498
     *                                               will fallback to this.
499
     * @param  string|null             $graphVersion The Graph API version to use.
500
     * @return FacebookBatchRequest
501
     */
502
    public function newBatchRequest($accessToken = null, $graphVersion = null)
503
    {
504
        $accessToken = $accessToken ?: $this->defaultAccessToken;
505
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
506
507
        return new FacebookBatchRequest(
508
            $this->app,
509
            [],
510
            $accessToken,
511
            $graphVersion
512
        );
513
    }
514
515
    /**
516
     * Instantiates a new FacebookRequest entity.
517
     *
518
     * @param string                  $method
519
     * @param string                  $endpoint
520
     * @param array                   $params
521
     * @param AccessToken|string|null $accessToken
522
     * @param string|null             $eTag
523
     * @param string|null             $graphVersion
524
     *
525
     * @return FacebookRequest
526
     *
527
     * @throws FacebookSDKException
528
     */
529
    public function request($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
530
    {
531
        $accessToken = $accessToken ?: $this->defaultAccessToken;
532
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
533
534
        return new FacebookRequest(
535
            $this->app,
536
            $accessToken,
537
            $method,
538
            $endpoint,
539
            $params,
540
            $eTag,
541
            $graphVersion
542
        );
543
    }
544
545
    /**
546
     * Factory to create FacebookFile's.
547
     *
548
     * @param string $pathToFile
549
     *
550
     * @return FacebookFile
551
     *
552
     * @throws FacebookSDKException
553
     */
554
    public function fileToUpload($pathToFile)
555
    {
556
        return new FacebookFile($pathToFile);
557
    }
558
559
    /**
560
     * Factory to create FacebookVideo's.
561
     *
562
     * @param string $pathToFile
563
     *
564
     * @return FacebookVideo
565
     *
566
     * @throws FacebookSDKException
567
     */
568
    public function videoToUpload($pathToFile)
569
    {
570
        return new FacebookVideo($pathToFile);
571
    }
572
573
    /**
574
     * Upload a video in chunks.
575
     *
576
     * @param int $target The id of the target node before the /videos edge.
577
     * @param string $pathToFile The full path to the file.
578
     * @param array $metadata The metadata associated with the video file.
579
     * @param string|null $accessToken The access token.
580
     * @param int $maxTransferTries The max times to retry a failed upload chunk.
581
     * @param string|null $graphVersion The Graph API version to use.
582
     *
583
     * @return array
584
     *
585
     * @throws FacebookSDKException
586
     */
587
    public function uploadVideo($target, $pathToFile, $metadata = [], $accessToken = null, $maxTransferTries = 5, $graphVersion = null)
588
    {
589
        $accessToken = $accessToken ?: $this->defaultAccessToken;
590
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
591
592
        $uploader = new FacebookResumableUploader($this->app, $this->client, $accessToken, $graphVersion);
593
        $endpoint = '/'.$target.'/videos';
594
        $file = $this->videoToUpload($pathToFile);
595
        $chunk = $uploader->start($endpoint, $file);
596
597
        do {
598
            $chunk = $this->maxTriesTransfer($uploader, $endpoint, $chunk, $maxTransferTries);
599
        } while (!$chunk->isLastChunk());
600
601
        return [
602
          'video_id' => $chunk->getVideoId(),
603
          'success' => $uploader->finish($endpoint, $chunk->getUploadSessionId(), $metadata),
604
        ];
605
    }
606
607
    /**
608
     * Attempts to upload a chunk of a file in $retryCountdown tries.
609
     *
610
     * @param FacebookResumableUploader $uploader
611
     * @param string $endpoint
612
     * @param FacebookTransferChunk $chunk
613
     * @param int $retryCountdown
614
     *
615
     * @return FacebookTransferChunk
616
     *
617
     * @throws FacebookSDKException
618
     */
619
    private function maxTriesTransfer(FacebookResumableUploader $uploader, $endpoint, FacebookTransferChunk $chunk, $retryCountdown)
620
    {
621
        $newChunk = $uploader->transfer($endpoint, $chunk, $retryCountdown < 1);
622
623
        if ($newChunk !== $chunk) {
624
            return $newChunk;
625
        }
626
627
        $retryCountdown--;
628
629
        // If transfer() returned the same chunk entity, the transfer failed but is resumable.
630
        return $this->maxTriesTransfer($uploader, $endpoint, $chunk, $retryCountdown);
631
    }
632
}
633