LinkedIn   B
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 351
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 71.17%

Importance

Changes 0
Metric Value
wmc 38
lcom 1
cbo 8
dl 0
loc 351
ccs 79
cts 111
cp 0.7117
rs 8.3999
c 0
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A isAuthenticated() 0 11 2
B api() 0 27 4
B filterRequestOption() 0 26 5
A getLoginUrl() 0 11 2
A get() 0 4 1
A post() 0 4 1
A clearStorage() 0 6 1
A hasError() 0 4 1
A getError() 0 6 2
A getFormat() 0 4 1
A setFormat() 0 6 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 setHttpMessageFactory() 0 6 1
A getRequestManager() 0 4 1
A getAuthenticator() 0 4 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 Http\Message\MessageFactory;
14
use Psr\Http\Message\ResponseInterface;
15
16
/**
17
 * Class LinkedIn lets you talk to LinkedIn api.
18
 *
19
 * When a new user arrives and want to authenticate here is whats happens:
20
 * 1. You redirect him to whatever url getLoginUrl() returns.
21
 * 2. The user logs in on www.linkedin.com and authorize your application.
22
 * 3. The user returns to your site with a *code* in the the $_REQUEST.
23
 * 4. You call isAuthenticated() or getAccessToken()
24
 * 5. If we don't have an access token (only a *code*), getAccessToken() will call fetchNewAccessToken()
25
 * 6. fetchNewAccessToken() gets the *code* from the $_REQUEST and calls getAccessTokenFromCode()
26
 * 7. getAccessTokenFromCode() makes a request to www.linkedin.com and exchanges the *code* for an access token
27
 * 8. When you have the access token you should store it in a database and/or query the API.
28
 * 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
29
 *    authentication steps again.
30
 *
31
 * @author Tobias Nyholm <[email protected]>
32
 */
33
class LinkedIn implements LinkedInInterface
34
{
35
    /**
36
     * The OAuth access token received in exchange for a valid authorization
37
     * code.  null means the access token has yet to be determined.
38
     *
39
     * @var AccessToken
40
     */
41
    protected $accessToken = null;
42
43
    /**
44
     * @var string format
45
     */
46
    private $format;
47
48
    /**
49
     * @var string responseFormat
50
     */
51
    private $responseDataType;
52
53
    /**
54
     * @var ResponseInterface
55
     */
56
    private $lastResponse;
57
58
    /**
59
     * @var RequestManager
60
     */
61
    private $requestManager;
62
63
    /**
64
     * @var Authenticator
65
     */
66
    private $authenticator;
67
68
    /**
69
     * @var UrlGeneratorInterface
70
     */
71
    private $urlGenerator;
72
73
    /**
74
     * Constructor.
75
     *
76
     * @param string $appId
77
     * @param string $appSecret
78
     * @param string $format           'json', 'xml'
79
     * @param string $responseDataType 'array', 'string', 'simple_xml' 'psr7', 'stream'
80
     */
81 7
    public function __construct($appId, $appSecret, $format = 'json', $responseDataType = 'array')
82
    {
83 7
        $this->format = $format;
84 7
        $this->responseDataType = $responseDataType;
85
86 7
        $this->requestManager = new RequestManager();
87 7
        $this->authenticator = new Authenticator($this->requestManager, $appId, $appSecret);
88 7
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93 1
    public function isAuthenticated()
94
    {
95 1
        $accessToken = $this->getAccessToken();
96 1
        if ($accessToken === null) {
97 1
            return false;
98
        }
99
100 1
        $user = $this->api('GET', '/v1/people/~:(id,firstName,lastName)', ['format' => 'json', 'response_data_type' => 'array']);
101
102 1
        return !empty($user['id']);
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108 1
    public function api($method, $resource, array $options = [])
109
    {
110
        // Add access token to the headers
111 1
        $options['headers']['Authorization'] = sprintf('Bearer %s', (string) $this->getAccessToken());
112
113
        // Do logic and adjustments to the options
114 1
        $requestFormat = $this->filterRequestOption($options);
115
116
        // Generate an url
117 1
        $url = $this->getUrlGenerator()->getUrl(
118 1
            'api',
119 1
            $resource,
120 1
            isset($options['query']) ? $options['query'] : []
121 1
        );
122
123 1
        $body = isset($options['body']) ? $options['body'] : null;
124 1
        $this->lastResponse = $this->getRequestManager()->sendRequest($method, $url, $options['headers'], $body);
125
126
        //Get the response data format
127 1
        if (isset($options['response_data_type'])) {
128
            $responseDataType = $options['response_data_type'];
129
        } else {
130 1
            $responseDataType = $this->getResponseDataType();
131
        }
132
133 1
        return ResponseConverter::convert($this->lastResponse, $requestFormat, $responseDataType);
134
    }
135
136
    /**
137
     * Modify and filter the request options. Make sure we use the correct query parameters and headers.
138
     *
139
     * @param array &$options
140
     *
141
     * @return string the request format to use
142
     */
143 1
    protected function filterRequestOption(array &$options)
144
    {
145 1
        if (isset($options['json'])) {
146 1
            $options['format'] = 'json';
147 1
            $options['body'] = json_encode($options['json']);
148 1
        } elseif (!isset($options['format'])) {
149
            // Make sure we always have a format
150
            $options['format'] = $this->getFormat();
151
        }
152
153
        // Set correct headers for this format
154 1
        switch ($options['format']) {
155 1
            case 'xml':
156
                $options['headers']['Content-Type'] = 'text/xml';
157
                break;
158 1
            case 'json':
159 1
                $options['headers']['Content-Type'] = 'application/json';
160 1
                $options['headers']['x-li-format'] = 'json';
161 1
                $options['query']['format'] = 'json';
162 1
                break;
163
            default:
164
                // Do nothing
165 1
        }
166
167 1
        return $options['format'];
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173 2
    public function getLoginUrl($options = [])
174
    {
175 2
        $urlGenerator = $this->getUrlGenerator();
176
177
        // Set redirect_uri to current URL if not defined
178 2
        if (!isset($options['redirect_uri'])) {
179 1
            $options['redirect_uri'] = $urlGenerator->getCurrentUrl();
180 1
        }
181
182 2
        return $this->getAuthenticator()->getLoginUrl($urlGenerator, $options);
183
    }
184
185
    /**
186
     * See docs for LinkedIn::api().
187
     *
188
     * @param string $resource
189
     * @param array  $options
190
     *
191
     * @return mixed
192
     */
193
    public function get($resource, array $options = [])
194
    {
195
        return $this->api('GET', $resource, $options);
196
    }
197
198
    /**
199
     * See docs for LinkedIn::api().
200
     *
201
     * @param string $resource
202
     * @param array  $options
203
     *
204
     * @return mixed
205
     */
206
    public function post($resource, array $options = [])
207
    {
208
        return $this->api('POST', $resource, $options);
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214
    public function clearStorage()
215
    {
216
        $this->getAuthenticator()->clearStorage();
217
218
        return $this;
219
    }
220
221
    /**
222
     * {@inheritdoc}
223
     */
224 3
    public function hasError()
225
    {
226 3
        return GlobalVariableGetter::has('error');
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232 2
    public function getError()
233
    {
234 2
        if ($this->hasError()) {
235 2
            return new LoginError(GlobalVariableGetter::get('error'), GlobalVariableGetter::get('error_description'));
236
        }
237 1
    }
238
239
    /**
240
     * Get the default format to use when sending requests.
241
     *
242
     * @return string
243
     */
244 1
    protected function getFormat()
245
    {
246 1
        return $this->format;
247
    }
248
249
    /**
250
     * {@inheritdoc}
251
     */
252 1
    public function setFormat($format)
253
    {
254 1
        $this->format = $format;
255
256 1
        return $this;
257
    }
258
259
    /**
260
     * Get the default data type to be returned as a response.
261
     *
262
     * @return string
263
     */
264 1
    protected function getResponseDataType()
265
    {
266 1
        return $this->responseDataType;
267
    }
268
269
    /**
270
     * {@inheritdoc}
271
     */
272
    public function setResponseDataType($responseDataType)
273
    {
274
        $this->responseDataType = $responseDataType;
275
276
        return $this;
277
    }
278
279
    /**
280
     * {@inheritdoc}
281
     */
282
    public function getLastResponse()
283
    {
284
        return $this->lastResponse;
285
    }
286
287
    /**
288
     * {@inheritdoc}
289
     */
290 1
    public function getAccessToken()
291
    {
292 1
        if ($this->accessToken === null) {
293 1
            if (null !== $newAccessToken = $this->getAuthenticator()->fetchNewAccessToken($this->getUrlGenerator())) {
294 1
                $this->setAccessToken($newAccessToken);
295 1
            }
296 1
        }
297
298
        // return the new access token or null if none found
299 1
        return $this->accessToken;
300
    }
301
302
    /**
303
     * {@inheritdoc}
304
     */
305 1
    public function setAccessToken($accessToken)
306
    {
307 1
        if (!($accessToken instanceof AccessToken)) {
308 1
            $accessToken = new AccessToken($accessToken);
309 1
        }
310
311 1
        $this->accessToken = $accessToken;
312
313 1
        return $this;
314
    }
315
316
    /**
317
     * {@inheritdoc}
318
     */
319 1
    public function setUrlGenerator(UrlGeneratorInterface $urlGenerator)
320
    {
321 1
        $this->urlGenerator = $urlGenerator;
322
323 1
        return $this;
324
    }
325
326
    /**
327
     * @return UrlGeneratorInterface
328
     */
329 2
    protected function getUrlGenerator()
330
    {
331 2
        if ($this->urlGenerator === null) {
332 2
            $this->urlGenerator = new UrlGenerator();
333 2
        }
334
335 2
        return $this->urlGenerator;
336
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341
    public function setStorage(DataStorageInterface $storage)
342
    {
343
        $this->getAuthenticator()->setStorage($storage);
344
345
        return $this;
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351
    public function setHttpClient(HttpClient $client)
352
    {
353
        $this->getRequestManager()->setHttpClient($client);
354
355
        return $this;
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361
    public function setHttpMessageFactory(MessageFactory $factory)
362
    {
363
        $this->getRequestManager()->setMessageFactory($factory);
364
365
        return $this;
366
    }
367
368
    /**
369
     * @return RequestManager
370
     */
371
    protected function getRequestManager()
372
    {
373
        return $this->requestManager;
374
    }
375
376
    /**
377
     * @return Authenticator
378
     */
379
    protected function getAuthenticator()
380
    {
381
        return $this->authenticator;
382
    }
383
}
384