Completed
Pull Request — master (#73)
by Tobias
03:11 queued 51s
created

LinkedIn   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 404
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 25
Bugs 6 Features 2
Metric Value
wmc 37
c 25
b 6
f 2
lcom 1
cbo 8
dl 0
loc 404
rs 8.6

23 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A isAuthenticated() 0 11 2
A getLoginUrl() 0 11 2
A post() 0 4 1
A clearStorage() 0 6 1
A getError() 0 6 2
A getFormat() 0 4 1
A getResponseDataType() 0 4 1
A setResponseDataType() 0 6 1
A getLastResponse() 0 4 1
A getAccessToken() 0 11 3
A setAccessToken() 0 10 2
A setUrlGenerator() 0 6 1
A getUrlGenerator() 0 8 2
A setStorage() 0 6 1
A setHttpClient() 0 6 1
A getRequestManager() 0 4 1
A getAuthenticator() 0 4 1
B api() 0 27 4
B filterRequestOption() 0 26 5
A get() 0 4 1
A hasError() 0 4 1
A setFormat() 0 6 1
1
<?php
2
3
namespace Happyr\LinkedIn;
4
5
use Happyr\LinkedIn\Exception\LoginError;
6
use Happyr\LinkedIn\Http\GlobalVariableGetter;
7
use Happyr\LinkedIn\Http\RequestManager;
8
use Happyr\LinkedIn\Http\ResponseConverter;
9
use Happyr\LinkedIn\Http\UrlGenerator;
10
use Happyr\LinkedIn\Http\UrlGeneratorInterface;
11
use Happyr\LinkedIn\Storage\DataStorageInterface;
12
use Http\Client\HttpClient;
13
use Psr\Http\Message\ResponseInterface;
14
15
/**
16
 * Class LinkedIn lets you talk to LinkedIn api.
17
 *
18
 * When a new user arrives and want to authenticate here is whats happens:
19
 * 1. You redirect him to whatever url getLoginUrl() returns.
20
 * 2. The user logs in on www.linkedin.com and authorize your application.
21
 * 3. The user returns to your site with a *code* in the the $_REQUEST.
22
 * 4. You call isAuthenticated() or getAccessToken()
23
 * 5. We don't got an access token (only a *code*). So getAccessToken() calls fetchNewAccessToken()
24
 * 6. fetchNewAccessToken() gets the *code* from the $_REQUEST and calls getAccessTokenFromCode()
25
 * 7. getAccessTokenFromCode() makes a request to www.linkedin.com and exchanges the *code* for an access token
26
 * 8. When you have the access token you should store it in a database and/or query the API.
27
 * 9. When you make a second request to the API we have the access token in memory, so we don't go through all these
28
 *    authentication steps again.
29
 *
30
 * @author Tobias Nyholm
31
 */
32
class LinkedIn
33
{
34
    /**
35
     * The OAuth access token received in exchange for a valid authorization
36
     * code.  null means the access token has yet to be determined.
37
     *
38
     * @var AccessToken
39
     */
40
    protected $accessToken = null;
41
42
    /**
43
     * @var string format
44
     */
45
    private $format;
46
47
    /**
48
     * @var string responseFormat
49
     */
50
    private $responseDataType;
51
52
    /**
53
     * @var ResponseInterface
54
     */
55
    private $lastResponse;
56
57
    /**
58
     * @var RequestManager
59
     */
60
    private $requestManager;
61
62
    /**
63
     * @var Authenticator
64
     */
65
    private $authenticator;
66
67
    /**
68
     * @var UrlGeneratorInterface
69
     */
70
    private $urlGenerator;
71
72
    /**
73
     * Constructor.
74
     *
75
     * @param string $appId
76
     * @param string $appSecret
77
     * @param string $format           'json', 'xml'
78
     * @param string $responseDataType 'array', 'string', 'simple_xml' 'psr7', 'stream'
79
     */
80
    public function __construct($appId, $appSecret, $format = 'json', $responseDataType = 'array')
81
    {
82
        $this->format = $format;
83
        $this->responseDataType = $responseDataType;
84
85
        $this->requestManager = new RequestManager();
86
        $this->authenticator = new Authenticator($this->requestManager, $appId, $appSecret);
87
    }
88
89
    /**
90
     * Is the current user authenticated?
91
     *
92
     * @return bool
93
     */
94
    public function isAuthenticated()
95
    {
96
        $accessToken = $this->getAccessToken();
97
        if ($accessToken === null) {
98
            return false;
99
        }
100
101
        $user = $this->api('GET', '/v1/people/~:(id,firstName,lastName)', array('format' => 'json', 'response_data_type' => 'array'));
102
103
        return !empty($user['id']);
104
    }
105
106
    /**
107
     * Make an API call. Read about what calls that are possible here: https://developer.linkedin.com/docs/rest-api.
108
     *
109
     * Example:
110
     * $linkedIn->api('GET', '/v1/people/~:(id,firstName,lastName,headline)');
111
     *
112
     * The options:
113
     * - body: the body of the request
114
     * - format: the format you are using to send the request
115
     * - headers: array with headers to use
116
     * - response_data_type: the data type to get back
117
     * - query: query parameters to the request
118
     *
119
     * @param string $method   This is the HTTP verb
120
     * @param string $resource everything after the domain in the URL.
121
     * @param array  $options  See the readme for option description.
122
     *
123
     * @return mixed this depends on the response_data_type parameter.
124
     */
125
    public function api($method, $resource, array $options = array())
126
    {
127
        // Add access token to the headers
128
        $options['headers']['Authorization'] = sprintf('Bearer %s', (string) $this->getAccessToken());
129
130
        // Do logic and adjustments to the options
131
        $requestFormat = $this->filterRequestOption($options);
132
133
        // Generate an url
134
        $url = $this->getUrlGenerator()->getUrl(
135
            'api',
136
            $resource,
137
            isset($options['query']) ? $options['query'] : array()
138
        );
139
140
        $body = isset($options['body']) ? $options['body'] : null;
141
        $this->lastResponse = $this->getRequestManager()->sendRequest($method, $url, $options['headers'], $body);
142
143
        //Get the response data format
144
        if (isset($options['response_data_type'])) {
145
            $responseDataType = $options['response_data_type'];
146
        } else {
147
            $responseDataType = $this->getResponseDataType();
148
        }
149
150
        return ResponseConverter::convert($this->lastResponse, $requestFormat, $responseDataType);
151
    }
152
153
    /**
154
     * Modify and filter the request options. Make sure we use the correct query parameters and headers.
155
     *
156
     * @param array &$options
157
     *
158
     * @return string the request format to use
159
     */
160
    protected function filterRequestOption(array &$options)
161
    {
162
        if (isset($options['json'])) {
163
            $options['format'] = 'json';
164
            $options['body'] = json_encode($options['json']);
165
        } elseif (!isset($options['format'])) {
166
            // Make sure we always have a format
167
            $options['format'] = $this->getFormat();
168
        }
169
170
        // Set correct headers for this format
171
        switch ($options['format']) {
172
            case 'xml':
173
                $options['headers']['Content-Type'] = 'text/xml';
174
                break;
175
            case 'json':
176
                $options['headers']['Content-Type'] = 'application/json';
177
                $options['headers']['x-li-format'] = 'json';
178
                $options['query']['format'] = 'json';
179
                break;
180
            default:
181
                // Do nothing
182
        }
183
184
        return $options['format'];
185
    }
186
187
    /**
188
     * Get a login URL where the user can put his/hers LinkedIn credentials and authorize the application.
189
     *
190
     * The options:
191
     * - redirect_uri: the url to go to after a successful login
192
     * - scope: comma (or space) separated list of requested extended permissions
193
     *
194
     * @param array $options Provide custom parameters
195
     *
196
     * @return string The URL for the login flow
197
     */
198
    public function getLoginUrl($options = array())
199
    {
200
        $urlGenerator = $this->getUrlGenerator();
201
202
        // Set redirect_uri to current URL if not defined
203
        if (!isset($options['redirect_uri'])) {
204
            $options['redirect_uri'] = $urlGenerator->getCurrentUrl();
205
        }
206
207
        return $this->getAuthenticator()->getLoginUrl($urlGenerator, $options);
208
    }
209
210
    /**
211
     * See docs for LinkedIn::api().
212
     *
213
     * @param string $resource
214
     * @param array  $options
215
     *
216
     * @return mixed
217
     */
218
    public function get($resource, array $options = array())
219
    {
220
        return $this->api('GET', $resource, $options);
221
    }
222
223
    /**
224
     * See docs for LinkedIn::api().
225
     *
226
     * @param string $resource
227
     * @param array  $options
228
     *
229
     * @return mixed
230
     */
231
    public function post($resource, array $options = array())
232
    {
233
        return $this->api('POST', $resource, $options);
234
    }
235
236
    /**
237
     * Clear the data storage. This will forget everything about the user and authentication process.
238
     *
239
     * @return $this
240
     */
241
    public function clearStorage()
242
    {
243
        $this->getAuthenticator()->clearStorage();
244
245
        return $this;
246
    }
247
248
    /**
249
     * If the user has canceled the login we will return with an error.
250
     *
251
     * @return bool
252
     */
253
    public function hasError()
254
    {
255
        return GlobalVariableGetter::has('error');
256
    }
257
258
    /**
259
     * Returns a LoginError or null.
260
     *
261
     * @return LoginError|null
262
     */
263
    public function getError()
264
    {
265
        if ($this->hasError()) {
266
            return new LoginError(GlobalVariableGetter::get('error'), GlobalVariableGetter::get('error_description'));
267
        }
268
    }
269
270
    /**
271
     * Get the default format to use when sending requests.
272
     *
273
     * @return string
274
     */
275
    public function getFormat()
276
    {
277
        return $this->format;
278
    }
279
280
    /**
281
     * Set the default format to use when sending requests.
282
     *
283
     * @param string $format
284
     *
285
     * @return $this
286
     */
287
    public function setFormat($format)
288
    {
289
        $this->format = $format;
290
291
        return $this;
292
    }
293
294
    /**
295
     * Get the default data type to be returned as a response.
296
     *
297
     * @return string
298
     */
299
    public function getResponseDataType()
300
    {
301
        return $this->responseDataType;
302
    }
303
304
    /**
305
     * Set the default data type to be returned as a response.
306
     *
307
     * @param string $responseDataType
308
     *
309
     * @return $this
310
     */
311
    public function setResponseDataType($responseDataType)
312
    {
313
        $this->responseDataType = $responseDataType;
314
315
        return $this;
316
    }
317
318
    /**
319
     * Get the last response. This will always return a PSR-7 response no matter of the data type used.
320
     *
321
     * @return ResponseInterface|null
322
     */
323
    public function getLastResponse()
324
    {
325
        return $this->lastResponse;
326
    }
327
328
    /**
329
     * Returns an access token. If we do not have one in memory, try to fetch one from a *code* in the $_REQUEST.
330
     *
331
     * @return AccessToken|null The access token of null if the access token is not found
332
     */
333
    public function getAccessToken()
334
    {
335
        if ($this->accessToken === null) {
336
            if (null !== $newAccessToken = $this->getAuthenticator()->fetchNewAccessToken($this->getUrlGenerator())) {
337
                $this->setAccessToken($newAccessToken);
338
            }
339
        }
340
341
        // return the new access token or null if none found
342
        return $this->accessToken;
343
    }
344
345
    /**
346
     * If you have stored a previous access token in a storage (database) you could set it here. After setting an
347
     * access token you have to make sure to verify it is still valid by running LinkedIn::isAuthenticated.
348
     *
349
     * @param string|AccessToken $accessToken
350
     *
351
     * @return $this
352
     */
353
    public function setAccessToken($accessToken)
354
    {
355
        if (!($accessToken instanceof AccessToken)) {
356
            $accessToken = new AccessToken($accessToken);
357
        }
358
359
        $this->accessToken = $accessToken;
360
361
        return $this;
362
    }
363
364
    /**
365
     * Set a URL generator.
366
     *
367
     * @param UrlGeneratorInterface $urlGenerator
368
     *
369
     * @return $this
370
     */
371
    public function setUrlGenerator(UrlGeneratorInterface $urlGenerator)
372
    {
373
        $this->urlGenerator = $urlGenerator;
374
375
        return $this;
376
    }
377
378
    /**
379
     * @return UrlGeneratorInterface
380
     */
381
    protected function getUrlGenerator()
382
    {
383
        if ($this->urlGenerator === null) {
384
            $this->urlGenerator = new UrlGenerator();
385
        }
386
387
        return $this->urlGenerator;
388
    }
389
390
    /**
391
     * Set a data storage.
392
     *
393
     * @param DataStorageInterface $storage
394
     *
395
     * @return $this
396
     */
397
    public function setStorage(DataStorageInterface $storage)
398
    {
399
        $this->getAuthenticator()->setStorage($storage);
400
401
        return $this;
402
    }
403
404
    /**
405
     * Set a http client.
406
     *
407
     * @param HttpClient $client
408
     *
409
     * @return $this
410
     *
411
     * @deprecated This function will be removed in 0.7.0. It will be replaced by setHttpAdapter
412
     */
413
    public function setHttpClient(HttpClient $client)
414
    {
415
        $this->getRequestManager()->setHttpClient($client);
416
417
        return $this;
418
    }
419
420
    /**
421
     * @return RequestManager
422
     */
423
    protected function getRequestManager()
424
    {
425
        return $this->requestManager;
426
    }
427
428
    /**
429
     * @return Authenticator
430
     */
431
    protected function getAuthenticator()
432
    {
433
        return $this->authenticator;
434
    }
435
}
436