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

LinkedIn::api()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 12
Bugs 2 Features 0
Metric Value
c 12
b 2
f 0
dl 0
loc 27
rs 8.5806
cc 4
eloc 14
nc 4
nop 3
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* and calls getAccessTokenFromCode()
25
 * 7. getAccessTokenFromCode() makes a request to www.linkedin.com and exchanges the *code* for an access token
26
 * 8. With a valid access token we can query the api for the user
27
 * 9. When you make a second request to the api you skip the authorization (1-3) and
28
 *     the "*code* for access token exchange" (5-7).
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('responseDataType' => 'array'));
102
103
        return !empty($user['id']);
104
    }
105
106
    /**
107
     * Make an API call.
108
     *
109
     * $linkedIn->api('GET', '/v1/people/~:(id,firstName,lastName,headline)');
110
     *
111
     * @param string $method   This is the HTTP verb
112
     * @param string $resource everything after the domain in the URL.
113
     * @param array  $options  [optional] This is the options you may pass to the request. You might be interested
114
     *                         in setting values for 'query', 'headers', 'body' or 'response_data_type'. See the readme for more.
115
     *
116
     * @return array|\SimpleXMLElement|string What the function return depends on the responseDataType parameter.
117
     */
118
    public function api($method, $resource, array $options = array())
119
    {
120
        // Add access token to the headers
121
        $options['headers']['Authorization'] = sprintf('Bearer %s', (string) $this->getAccessToken());
122
123
        // Do logic and adjustments to the options
124
        $requestFormat = $this->filterRequestOption($options);
125
126
        // Generate an url
127
        $url = $this->getUrlGenerator()->getUrl(
128
            'api',
129
            $resource,
130
            isset($options['query']) ? $options['query'] : array()
131
        );
132
133
        //Get the response data format
134
        if (isset($options['response_data_type'])) {
135
            $responseDataType = $options['response_data_type'];
136
        } else {
137
            $responseDataType = $this->getResponseDataType();
138
        }
139
140
        $body = isset($options['body']) ? $options['body'] : null;
141
        $this->lastResponse = $this->getRequestManager()->sendRequest($method, $url, $options['headers'], $body);
142
143
        return ResponseConverter::convert($this->lastResponse, $requestFormat, $responseDataType);
144
    }
145
146
    /**
147
     * Modify and filter the request options. Make sure we use the correct query parameters and headers.
148
     *
149
     * @param array &$options
150
     *
151
     * @return string the request format to use
152
     */
153
    protected function filterRequestOption(array &$options)
154
    {
155
        if (isset($options['json'])) {
156
            $options['format'] = 'json';
157
            $options['body'] = json_encode($options['json']);
158
        } elseif (!isset($options['format'])) {
159
            $options['format'] = $this->getFormat();
160
        }
161
162
        // Set correct headers for this format
163
        switch ($options['format']) {
164
            case 'xml':
165
                $options['headers']['Content-Type'] = 'text/xml';
166
                break;
167
            case 'json':
168
                $options['headers']['Content-Type'] = 'application/json';
169
                $options['headers']['x-li-format'] = 'json';
170
                $options['query']['format'] = 'json';
171
                break;
172
            default:
173
                // Do nothing
174
        }
175
176
        return $options['format'];
177
    }
178
179
    /**
180
     * Get a Login URL for use with redirects. By default, full page redirect is
181
     * assumed. If you are using the generated URL with a window.open() call in
182
     * JavaScript, you can pass in display=popup as part of the $params.
183
     *
184
     * The parameters:
185
     * - redirect_uri: the url to go to after a successful login
186
     * - scope: comma (or space) separated list of requested extended permissions
187
     *
188
     * @param array $options Provide custom parameters
189
     *
190
     * @return string The URL for the login flow
191
     */
192
    public function getLoginUrl($options = array())
193
    {
194
        return $this->getAuthenticator()->getLoginUrl($this->getUrlGenerator(), $options);
195
    }
196
197
    /**
198
     * See docs for LinkedIn::api.
199
     *
200
     * @param string $resource
201
     * @param array  $options
202
     *
203
     * @return array|\SimpleXMLElement|string
204
     */
205
    public function get($resource, array $options = array())
206
    {
207
        return $this->api('GET', $resource, $options);
208
    }
209
210
    /**
211
     * See docs for LinkedIn::api.
212
     *
213
     * @param string $resource
214
     * @param array  $options
215
     *
216
     * @return array|\SimpleXMLElement|string
217
     */
218
    public function post($resource, array $options = array())
219
    {
220
        return $this->api('POST', $resource, $options);
221
    }
222
223
    /**
224
     * Clear the storage. This will forget everything about the user and authentication process.
225
     *
226
     * @return $this
227
     */
228
    public function clearStorage()
229
    {
230
        $this->getAuthenticator()->clearStorage();
231
232
        return $this;
233
    }
234
235
    /**
236
     * If the user has canceled the login we will return with an error.
237
     *
238
     * @return bool
239
     */
240
    public function hasError()
241
    {
242
        return GlobalVariableGetter::has('error');
243
    }
244
245
    /**
246
     * Returns a LoginError or null.
247
     *
248
     * @return LoginError|null
249
     */
250
    public function getError()
251
    {
252
        if ($this->hasError()) {
253
            return new LoginError(GlobalVariableGetter::get('error'), GlobalVariableGetter::get('error_description'));
254
        }
255
    }
256
257
    /**
258
     * @return string
259
     */
260
    public function getFormat()
261
    {
262
        return $this->format;
263
    }
264
265
    /**
266
     * @param string $format
267
     *
268
     * @return $this
269
     */
270
    public function setFormat($format)
271
    {
272
        $this->format = $format;
273
274
        return $this;
275
    }
276
277
    /**
278
     * @return string
279
     */
280
    public function getResponseDataType()
281
    {
282
        return $this->responseDataType;
283
    }
284
285
    /**
286
     * @param string $responseDataType
287
     *
288
     * @return $this
289
     */
290
    public function setResponseDataType($responseDataType)
291
    {
292
        $this->responseDataType = $responseDataType;
293
294
        return $this;
295
    }
296
297
    /**
298
     * Get headers from last response.
299
     *
300
     * @return array
301
     */
302
    public function getLastHeaders()
303
    {
304
        if ($this->lastResponse === null) {
305
            return [];
306
        }
307
308
        return $this->lastResponse->getHeaders();
309
    }
310
311
    /**
312
     * Determines the access token that should be used for API calls.
313
     *
314
     * @return AccessToken|null The access token of null if the access token is not found
315
     */
316
    public function getAccessToken()
317
    {
318
        if ($this->accessToken === null) {
319
            $newAccessToken = $this->getAuthenticator()->fetchNewAccessToken($this->getUrlGenerator());
320
            if ($newAccessToken !== null) {
321
                $this->setAccessToken($newAccessToken);
322
            }
323
        }
324
325
        // return the new access token or null if none found
326
        return $this->accessToken;
327
    }
328
329
    /**
330
     * Get the access token.
331
     *
332
     * @param string|AccessToken $accessToken
333
     *
334
     * @return $this
335
     */
336
    public function setAccessToken($accessToken)
337
    {
338
        if (!($accessToken instanceof AccessToken)) {
339
            $accessToken = new AccessToken($accessToken);
340
        }
341
342
        $this->accessToken = $accessToken;
343
344
        return $this;
345
    }
346
347
    /**
348
     * @param UrlGeneratorInterface $urlGenerator
349
     *
350
     * @return $this
351
     */
352
    public function setUrlGenerator(UrlGeneratorInterface $urlGenerator)
353
    {
354
        $this->urlGenerator = $urlGenerator;
355
356
        return $this;
357
    }
358
359
    /**
360
     * @return UrlGeneratorInterface
361
     */
362
    protected function getUrlGenerator()
363
    {
364
        if ($this->urlGenerator === null) {
365
            $this->urlGenerator = new UrlGenerator();
366
        }
367
368
        return $this->urlGenerator;
369
    }
370
371
    /**
372
     * @param DataStorageInterface $storage
373
     *
374
     * @return $this
375
     */
376
    public function setStorage(DataStorageInterface $storage)
377
    {
378
        $this->getAuthenticator()->setStorage($storage);
379
380
        return $this;
381
    }
382
383
    /**
384
     * @param HttpClient $client
385
     *
386
     * @return $this
387
     */
388
    public function setHttpClient(HttpClient $client)
389
    {
390
        $this->getRequestManager()->setHttpClient($client);
391
392
        return $this;
393
    }
394
395
    /**
396
     * @return RequestManager
397
     */
398
    protected function getRequestManager()
399
    {
400
        return $this->requestManager;
401
    }
402
403
    /**
404
     * @return Authenticator
405
     */
406
    protected function getAuthenticator()
407
    {
408
        return $this->authenticator;
409
    }
410
}
411