Completed
Pull Request — master (#151)
by
unknown
08:15
created

LinkedIn::setRequestManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
344
345
        return $this;
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351
    public function setStorage(DataStorageInterface $storage)
352
    {
353
        $this->getAuthenticator()->setStorage($storage);
354
355
        return $this;
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361
    public function setHttpClient(HttpClient $client)
362
    {
363
        $this->getRequestManager()->setHttpClient($client);
364
365
        return $this;
366
    }
367
368
    /**
369
     * {@inheritdoc}
370
     */
371
    public function setHttpMessageFactory(MessageFactory $factory)
372
    {
373
        $this->getRequestManager()->setMessageFactory($factory);
374
375
        return $this;
376
    }
377
378
    /**
379
     * @return RequestManager
380
     */
381
    protected function getRequestManager()
382
    {
383
        return $this->requestManager;
384
    }
385
386
    /**
387
     * @return Authenticator
388
     */
389
    protected function getAuthenticator()
390
    {
391
        return $this->authenticator;
392
    }
393
394
    /**
395
     * @return Authenticator
396
     */
397
    public function setAuthenticator(AuthenticatorInterface $auth)
398
    {
399
        $this->authenticator = $auth;
0 ignored issues
show
Documentation Bug introduced by
$auth is of type object<Happyr\LinkedIn\AuthenticatorInterface>, but the property $authenticator was declared to be of type object<Happyr\LinkedIn\Authenticator>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
400
        return $this;
401
    }
402
}
403