Instagram::getDefaultAccessToken()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright 2017 Instagram, 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
 * Instagram.
9
 *
10
 * As with any software that integrates with the Instagram platform, your use
11
 * of this software is subject to the Instagram Developer Principles and
12
 * Policies [http://developers.instagram.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 Maztech;
25
26
use Maztech\Authentication\AccessToken;
27
use Maztech\Authentication\OAuth2Client;
28
use Maztech\Exceptions\InstagramSDKException;
29
use Maztech\GraphNodes\GraphEdge;
30
use Maztech\Helpers\InstagramRedirectLoginHelper;
31
use Maztech\HttpClients\HttpClientsFactory;
32
use Maztech\PersistentData\PersistentDataFactory;
33
use Maztech\PseudoRandomString\PseudoRandomStringGeneratorFactory;
34
use Maztech\Url\InstagramUrlDetectionHandler;
35
use Maztech\Url\UrlDetectionInterface;
36
37
/**
38
 * Class Instagram
39
 *
40
 * @package Instagram
41
 */
42
class Instagram
43
{
44
    /**
45
     * @const string Version number of the Instagram PHP SDK.
46
     */
47
    const VERSION = '1.0.0';
48
49
    /**
50
     * @const string Default Graph API version for requests.
51
     */
52
    const DEFAULT_GRAPH_VERSION = 'v8.0';
53
54
    /**
55
     * @const string The name of the environment variable that contains the app ID.
56
     */
57
    const APP_ID_ENV_NAME = 'INSTAGRAM_APP_ID';
58
59
    /**
60
     * @const string The name of the environment variable that contains the app secret.
61
     */
62
    const APP_SECRET_ENV_NAME = 'INSTAGRAM_APP_SECRET';
63
64
    /**
65
     * @var InstagramApp The InstagramApp entity.
66
     */
67
    protected $app;
68
69
    /**
70
     * @var InstagramClient The Instagram client service.
71
     */
72
    protected $client;
73
74
    /**
75
     * @var OAuth2Client The OAuth 2.0 client service.
76
     */
77
    protected $oAuth2Client;
78
79
    /**
80
     * @var UrlDetectionInterface|null The URL detection handler.
81
     */
82
    protected $urlDetectionHandler;
83
84
    /**
85
     * @var PseudoRandomStringGeneratorInterface|null The cryptographically secure pseudo-random string generator.
0 ignored issues
show
Bug introduced by
The type Maztech\PseudoRandomStringGeneratorInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
86
     */
87
    protected $pseudoRandomStringGenerator;
88
89
    /**
90
     * @var AccessToken|null The default access token to use with requests.
91
     */
92
    protected $defaultAccessToken;
93
94
    /**
95
     * @var string|null The default Graph version we want to use.
96
     */
97
    protected $defaultGraphVersion;
98
99
    /**
100
     * @var PersistentDataInterface|null The persistent data handler.
0 ignored issues
show
Bug introduced by
The type Maztech\PersistentDataInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
101
     */
102
    protected $persistentDataHandler;
103
104
    /**
105
     * @var InstagramResponse|InstagramBatchResponse|null Stores the last request made to Graph.
106
     */
107
    protected $lastResponse;
108
109
    /**
110
     * Instantiates a new Instagram super-class object.
111
     *
112
     * @param array $config
113
     *
114
     * @throws InstagramSDKException
115
     */
116
    public function __construct(array $config = [])
117
    {
118
        $config = array_merge([
119
            'app_id' => getenv(static::APP_ID_ENV_NAME),
120
            'app_secret' => getenv(static::APP_SECRET_ENV_NAME),
121
            'http_client_handler' => null,
122
            'persistent_data_handler' => null,
123
            'pseudo_random_string_generator' => null,
124
            'url_detection_handler' => null,
125
        ], $config);
126
127
        if (!$config['app_id']) {
128
            throw new InstagramSDKException('Required "app_id" key not supplied in config and could not find fallback environment variable "' . static::APP_ID_ENV_NAME . '"');
129
        }
130
        if (!$config['app_secret']) {
131
            throw new InstagramSDKException('Required "app_secret" key not supplied in config and could not find fallback environment variable "' . static::APP_SECRET_ENV_NAME . '"');
132
        }
133
134
        $this->app = new InstagramApp($config['app_id'], $config['app_secret']);
135
        $this->client = new InstagramClient(
136
            HttpClientsFactory::createHttpClient($config['http_client_handler'])
137
        );
138
        $this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator(
0 ignored issues
show
Documentation Bug introduced by
It seems like Maztech\PseudoRandomStri...dom_string_generator']) of type Maztech\PseudoRandomStri...tringGeneratorInterface is incompatible with the declared type Maztech\PseudoRandomStringGeneratorInterface|null of property $pseudoRandomStringGenerator.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
139
            $config['pseudo_random_string_generator']
140
        );
141
        $this->setUrlDetectionHandler($config['url_detection_handler'] ?: new InstagramUrlDetectionHandler());
142
        $this->persistentDataHandler = PersistentDataFactory::createPersistentDataHandler(
0 ignored issues
show
Documentation Bug introduced by
It seems like Maztech\PersistentData\P...sistent_data_handler']) of type Maztech\PersistentData\PersistentDataInterface is incompatible with the declared type Maztech\PersistentDataInterface|null of property $persistentDataHandler.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
143
            $config['persistent_data_handler']
144
        );
145
146
        if (isset($config['default_access_token'])) {
147
            $this->setDefaultAccessToken($config['default_access_token']);
148
        }
149
    }
150
151
    /**
152
     * Returns the InstagramApp entity.
153
     *
154
     * @return InstagramApp
155
     */
156
    public function getApp()
157
    {
158
        return $this->app;
159
    }
160
161
    /**
162
     * Returns the InstagramClient service.
163
     *
164
     * @return InstagramClient
165
     */
166
    public function getClient()
167
    {
168
        return $this->client;
169
    }
170
171
    /**
172
     * Returns the OAuth 2.0 client service.
173
     *
174
     * @return OAuth2Client
175
     */
176
    public function getOAuth2Client()
177
    {
178
        if (!$this->oAuth2Client instanceof OAuth2Client) {
0 ignored issues
show
introduced by
$this->oAuth2Client is always a sub-type of Maztech\Authentication\OAuth2Client.
Loading history...
179
            $app = $this->getApp();
180
            $client = $this->getClient();
181
            $this->oAuth2Client = new OAuth2Client($app, $client, $this->defaultGraphVersion);
182
        }
183
184
        return $this->oAuth2Client;
185
    }
186
187
    /**
188
     * Returns the last response returned from Graph.
189
     *
190
     * @return InstagramResponse|InstagramBatchResponse|null
191
     */
192
    public function getLastResponse()
193
    {
194
        return $this->lastResponse;
195
    }
196
197
    /**
198
     * Returns the URL detection handler.
199
     *
200
     * @return UrlDetectionInterface
201
     */
202
    public function getUrlDetectionHandler()
203
    {
204
        return $this->urlDetectionHandler;
205
    }
206
207
    /**
208
     * Changes the URL detection handler.
209
     *
210
     * @param UrlDetectionInterface $urlDetectionHandler
211
     */
212
    private function setUrlDetectionHandler(UrlDetectionInterface $urlDetectionHandler)
213
    {
214
        $this->urlDetectionHandler = $urlDetectionHandler;
215
    }
216
217
    /**
218
     * Returns the default AccessToken entity.
219
     *
220
     * @return AccessToken|null
221
     */
222
    public function getDefaultAccessToken()
223
    {
224
        return $this->defaultAccessToken;
225
    }
226
227
    /**
228
     * Sets the default access token to use with requests.
229
     *
230
     * @param AccessToken|string $accessToken The access token to save.
231
     *
232
     * @throws \InvalidArgumentException
233
     */
234
    public function setDefaultAccessToken($accessToken)
235
    {
236
        if (is_string($accessToken)) {
237
            $this->defaultAccessToken = new AccessToken($accessToken);
238
239
            return;
240
        }
241
242
        if ($accessToken instanceof AccessToken) {
0 ignored issues
show
introduced by
$accessToken is always a sub-type of Maztech\Authentication\AccessToken.
Loading history...
243
            $this->defaultAccessToken = $accessToken;
244
245
            return;
246
        }
247
248
        throw new \InvalidArgumentException('The default access token must be of type "string" or Instagram\AccessToken');
249
    }
250
251
    /**
252
     * Returns the default Graph version.
253
     *
254
     * @return string
255
     */
256
    public function getDefaultGraphVersion()
257
    {
258
        return $this->defaultGraphVersion;
259
    }
260
261
    /**
262
     * Returns the redirect login helper.
263
     *
264
     * @return InstagramRedirectLoginHelper
265
     */
266
    public function getRedirectLoginHelper()
267
    {
268
        return new InstagramRedirectLoginHelper(
269
            $this->getOAuth2Client(),
270
            $this->persistentDataHandler,
271
            $this->urlDetectionHandler,
272
            $this->pseudoRandomStringGenerator
273
        );
274
    }
275
276
    /**
277
     * Sends a GET request to Graph and returns the result.
278
     *
279
     * @param string                  $endpoint
280
     * @param AccessToken|string|null $accessToken
281
     * @param string|null             $eTag
282
     *
283
     * @return InstagramResponse
284
     *
285
     * @throws InstagramSDKException
286
     */
287
    public function get($endpoint, $accessToken = null, $eTag = null)
288
    {
289
        return $this->sendRequest(
290
            'GET',
291
            $endpoint,
292
            $params = [],
293
            $accessToken,
294
            $eTag
295
        );
296
    }
297
298
    /**
299
     * Sends a POST request to Graph and returns the result.
300
     *
301
     * @param string                  $endpoint
302
     * @param array                   $params
303
     * @param AccessToken|string|null $accessToken
304
     * @param string|null             $eTag
305
     *
306
     * @return InstagramResponse
307
     *
308
     * @throws InstagramSDKException
309
     */
310
    public function post($endpoint, array $params = [], $accessToken = null, $eTag = null)
311
    {
312
        return $this->sendRequest(
313
            'POST',
314
            $endpoint,
315
            $params,
316
            $accessToken,
317
            $eTag
318
        );
319
    }
320
321
    /**
322
     * Sends a DELETE request to Graph and returns the result.
323
     *
324
     * @param string                  $endpoint
325
     * @param array                   $params
326
     * @param AccessToken|string|null $accessToken
327
     * @param string|null             $eTag
328
     *
329
     * @return InstagramResponse
330
     *
331
     * @throws InstagramSDKException
332
     */
333
    public function delete($endpoint, array $params = [], $accessToken = null, $eTag = null)
334
    {
335
        return $this->sendRequest(
336
            'DELETE',
337
            $endpoint,
338
            $params,
339
            $accessToken,
340
            $eTag
341
        );
342
    }
343
344
    /**
345
     * Sends a request to Graph for the next page of results.
346
     *
347
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
348
     *
349
     * @return GraphEdge|null
350
     *
351
     * @throws InstagramSDKException
352
     */
353
    public function next(GraphEdge $graphEdge)
354
    {
355
        return $this->getPaginationResults($graphEdge, 'next');
356
    }
357
358
    /**
359
     * Sends a request to Graph for the previous page of results.
360
     *
361
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
362
     *
363
     * @return GraphEdge|null
364
     *
365
     * @throws InstagramSDKException
366
     */
367
    public function previous(GraphEdge $graphEdge)
368
    {
369
        return $this->getPaginationResults($graphEdge, 'previous');
370
    }
371
372
    /**
373
     * Sends a request to Graph for the next page of results.
374
     *
375
     * @param GraphEdge $graphEdge The GraphEdge to paginate over.
376
     * @param string    $direction The direction of the pagination: next|previous.
377
     *
378
     * @return GraphEdge|null
379
     *
380
     * @throws InstagramSDKException
381
     */
382
    public function getPaginationResults(GraphEdge $graphEdge, $direction)
383
    {
384
        $paginationRequest = $graphEdge->getPaginationRequest($direction);
385
        if (!$paginationRequest) {
386
            return null;
387
        }
388
389
        $this->lastResponse = $this->client->sendRequest($paginationRequest);
390
391
        // Keep the same GraphNode subclass
392
        $subClassName = $graphEdge->getSubClassName();
393
        $graphEdge = $this->lastResponse->getGraphEdge($subClassName, false);
394
395
        return count($graphEdge) > 0 ? $graphEdge : null;
396
    }
397
398
    /**
399
     * Sends a request to Graph and returns the result.
400
     *
401
     * @param string                  $method
402
     * @param string                  $endpoint
403
     * @param array                   $params
404
     * @param AccessToken|string|null $accessToken
405
     * @param string|null             $eTag
406
     * @param string|null             $graphVersion
407
     *
408
     * @return InstagramResponse
409
     *
410
     * @throws InstagramSDKException
411
     */
412
    public function sendRequest($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
413
    {
414
        $accessToken = $accessToken ?: $this->defaultAccessToken;
415
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
416
        $request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion);
0 ignored issues
show
Unused Code introduced by
The call to Maztech\Instagram::request() has too many arguments starting with $graphVersion. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

416
        /** @scrutinizer ignore-call */ 
417
        $request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
417
418
        return $this->lastResponse = $this->client->sendRequest($request);
419
    }
420
421
    /**
422
     * Sends a batched request to Graph and returns the result.
423
     *
424
     * @param array                   $requests
425
     * @param AccessToken|string|null $accessToken
426
     * @param string|null             $graphVersion
427
     *
428
     * @return InstagramBatchResponse
429
     *
430
     * @throws InstagramSDKException
431
     */
432
    public function sendBatchRequest(array $requests, $accessToken = null, $graphVersion = null)
433
    {
434
        $accessToken = $accessToken ?: $this->defaultAccessToken;
435
        $graphVersion = $graphVersion ?: $this->defaultGraphVersion;
436
        $batchRequest = new InstagramBatchRequest(
437
            $this->app,
438
            $requests,
439
            $accessToken,
440
            $graphVersion
441
        );
442
443
        return $this->lastResponse = $this->client->sendBatchRequest($batchRequest);
444
    }
445
446
    /**
447
     * Instantiates an empty InstagramBatchRequest entity.
448
     *
449
     * @param  AccessToken|string|null $accessToken  The top-level access token. Requests with no access token
450
     *                                               will fallback to this.
451
     * @return InstagramBatchRequest
452
     */
453
    public function newBatchRequest($accessToken = null)
454
    {
455
        $accessToken = $accessToken ?: $this->defaultAccessToken;
456
457
        return new InstagramBatchRequest(
458
            $this->app,
459
            [],
460
            $accessToken
461
        );
462
    }
463
464
    /**
465
     * Instantiates a new InstagramRequest entity.
466
     *
467
     * @param string                  $method
468
     * @param string                  $endpoint
469
     * @param array                   $params
470
     * @param AccessToken|string|null $accessToken
471
     * @param string|null             $eTag
472
     * @param string|null             $graphVersion
473
     *
474
     * @return InstagramRequest
475
     *
476
     * @throws InstagramSDKException
477
     */
478
    public function request($method, $endpoint, array $params = [], $accessToken = null, $eTag = null)
479
    {
480
        $accessToken = $accessToken ?: $this->defaultAccessToken;
481
482
        return new InstagramRequest(
483
            $this->app,
484
            $accessToken,
485
            $method,
486
            $endpoint,
487
            $params,
488
            $eTag
489
        );
490
    }
491
}
492