Skip to content

Commit 795508c

Browse files
committed
feat: Use psr 17 & psr 18
1 parent 88e5db1 commit 795508c

9 files changed

Lines changed: 115 additions & 175 deletions

.php-cs-fixer.dist.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,6 @@
327327
'ternary_to_null_coalescing' => true,
328328
'trailing_comma_in_multiline' => [
329329
'elements' => [
330-
'arguments',
331330
'arrays',
332331
'match',
333332
]

Readme.md

Lines changed: 45 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
[![Latest Stable Version](https://poser.pugx.org/elninotech/linkedin-api-client/v)](https://packagist.org/packages/elninotech/linkedin-api-client)
66
[![Total Downloads](https://poser.pugx.org/elninotech/linkedin-api-client/downloads)](https://packagist.org/packages/elninotech/linkedin-api-client/stats)
77

8-
98
A PHP library to handle authentication and communication with LinkedIn API. The library/SDK helps you to get an access
109
token and when authenticated it helps you to send API requests. You will not get *everything* for free though... You
11-
have to read the [LinkedIn documentation][api-doc-core] to understand how you should query the API.
10+
have to read the [LinkedIn documentation][api-doc-core] to understand how you should query the API.
1211

1312
To get an overview what this library actually is doing for you. Take a look at the authentication page from
1413
the [API docs][api-doc-authentication].
@@ -19,55 +18,27 @@ Here is a list of features that might convince you to choose this LinkedIn clien
1918

2019
* Flexible and easy to extend
2120
* Developed with modern PHP standards
22-
* Not developed for a specific framework.
21+
* Not developed for a specific framework.
2322
* Handles the authentication process
2423
* Respects the CSRF protection
2524

2625
## Installation
2726

28-
**TL;DR**
29-
```bash
30-
composer require php-http/curl-client guzzlehttp/psr7 php-http/message elninotech/linkedin-api-client
31-
```
32-
33-
This library does not have a dependency on Guzzle or any other library that sends HTTP requests. We use the awesome
34-
HTTPlug to achieve the decoupling. We want you to choose what library to use for sending HTTP requests. Consult this list
35-
of packages that support [php-http/client-implementation](https://packagist.org/providers/php-http/client-implementation)
36-
find clients to use. For more information about virtual packages please refer to
37-
[HTTPlug](http://docs.php-http.org/en/latest/httplug/users.html). Example:
38-
39-
```bash
40-
composer require php-http/guzzle7-adapter
41-
```
42-
43-
You do also need to install a PSR-7 implementation and a factory to create PSR-7 messages (PSR-17 whenever that is
44-
released). You could use Guzzles PSR-7 implementation and factories from php-http:
27+
First, install Linkedin-API-client via the [Composer][composer] package manager:
4528

4629
```bash
47-
composer require guzzlehttp/psr7 php-http/message
30+
composer require elninotech/linkedin-api-client
4831
```
4932

50-
Now you may install the library by running the following:
33+
Ensure that the `php-http/discovery` composer plugin is allowed to run or install a client manually if your project does
34+
not already have a PSR-18 client integrated.
5135

5236
```bash
53-
composer require elninotech/linkedin-api-client
37+
composer require guzzlehttp/guzzle
5438
```
5539

5640
If you are updating from a previous version, make sure to read [the upgrade documentation](Upgrade.md).
5741

58-
### Finding the HTTP client (optional)
59-
60-
The LinkedIn client needs to know what library you are using to send HTTP messages. You could provide an instance of
61-
HttpClient and MessageFactory or you could fall back to auto discovery. Below is an example of where you provide a Guzzle7
62-
instance.
63-
64-
```php
65-
$linkedIn=new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret');
66-
$linkedIn->setHttpClient(new \Http\Adapter\Guzzle7\Client());
67-
$linkedIn->setHttpMessageFactory(new Http\Message\MessageFactory\GuzzleMessageFactory());
68-
69-
```
70-
7142
## Usage
7243

7344
In order to use this API client (or any other LinkedIn clients), you have to [register your application][register-app]
@@ -91,7 +62,7 @@ This example below is showing how to login with LinkedIn.
9162
*/
9263
//require_once "vendor/autoload.php";
9364

94-
$linkedIn=new Elnino\LinkedIn\LinkedIn('client_id', 'client_secret');
65+
$linkedIn = new Elnino\LinkedIn\LinkedIn('client_id', 'client_secret');
9566

9667
if ($linkedIn->isAuthenticated()) {
9768
//we know that the user is authenticated now. Start query the API
@@ -112,10 +83,10 @@ echo "<a href='$url'>Login with LinkedIn</a>";
11283

11384
### How to post on LinkedIn wall
11485

115-
The example below shows how you can post on a users wall. The access token is fetched from the database.
86+
The example below shows how you can post on a users wall. The access token is fetched from the database.
11687

11788
```php
118-
$linkedIn=new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret');
89+
$linkedIn = new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret');
11990
$linkedIn->setAccessToken('access_token_from_db');
12091

12192
$options = array('json'=>
@@ -142,15 +113,15 @@ var_dump($result);
142113

143114
### The api options
144115

145-
The third parameter of `LinkedIn::api` is an array with options. Below is a table of array keys that you may use.
116+
The third parameter of `LinkedIn::api` is an array with options. Below is a table of array keys that you may use.
146117

147-
| Option name | Description
148-
| ----------- | -----------
149-
| body | The body of a HTTP request. Put your json string here.
150-
| headers | This is HTTP headers to the request
151-
| json | This is an array with json data that will be encoded to a json string.
152-
| response_data_type | To override the response format for one request
153-
| query | This is an array with query parameters
118+
| Option name | Description
119+
|--------------------|------------------------------------------------------------------------
120+
| body | The body of a HTTP request. Put your json string here.
121+
| headers | This is HTTP headers to the request
122+
| json | This is an array with json data that will be encoded to a json string.
123+
| response_data_type | To override the response format for one request
124+
| query | This is an array with query parameters
154125

155126
### Understanding response data type
156127

@@ -159,7 +130,7 @@ The data type returned from `LinkedIn::api` can be configured. You may use the t
159130

160131
```php
161132
// By constructor argument
162-
$linkedIn=new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret', 'array');
133+
$linkedIn = new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret', 'array');
163134

164135
// By setter
165136
$linkedIn->setResponseDataType('string');
@@ -171,29 +142,29 @@ $linkedIn->get('/v2/me/?projection=(id,firstName,lastName)', array('response_dat
171142

172143
Below is a table that specifies what the possible return data types are when you call `LinkedIn::api`.
173144

174-
| Type | Description
175-
| ------ | ------------
176-
| array | An assosiative array. This can only be used with the `json` format.
177-
| psr7 | A PSR7 response.
178-
| stream | A file stream.
179-
| string | A plain old string.
180-
145+
| Type | Description
146+
|--------|---------------------------------------------------------------------
147+
| array | An assosiative array. This can only be used with the `json` format.
148+
| psr7 | A PSR7 response.
149+
| stream | A file stream.
150+
| string | A plain old string.
181151

182152
### Use different Session classes
183153

184154
You might want to use another storage than the default `SessionStorage`. If you are using Laravel
185-
you are more likely to inject the `IlluminateSessionStorage`.
155+
you are more likely to inject the `IlluminateSessionStorage`.
156+
186157
```php
187-
$linkedIn=new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret');
158+
$linkedIn = new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret');
188159
$linkedIn->setStorage(new IlluminateSessionStorage());
189160
```
190161

191162
You can inject any class implementing `DataStorageInterface`. You can also inject different `UrlGenerator` classes.
192163

193164
### Using different scopes
194165

195-
If you want to define special scopes when you authenticate the user you should specify them when you are generating the
196-
login url. If you don't specify scopes LinkedIn will use the default scopes that you have configured for the app.
166+
If you want to define special scopes when you authenticate the user you should specify them when you are generating the
167+
login url. If you don't specify scopes LinkedIn will use the default scopes that you have configured for the app.
197168

198169
```php
199170
$scope = 'r_fullprofile,r_emailaddress,w_share';
@@ -204,11 +175,26 @@ $url = $linkedIn->getLoginUrl(array('scope'=>$scope));
204175
echo "<a href='$url'>Login with LinkedIn</a>";
205176
```
206177

178+
### Using a different http client
179+
180+
If you want to customize how the requests are being sent, you can inject a different `RequestManager` when instantiating
181+
the API.
182+
183+
```php
184+
$myRequestManager = new MySpecialRequestManager();
185+
$linkedIn = new Elnino\LinkedIn\LinkedIn('app_id', 'app_secret', 'array', $myRequestManager);
186+
```
187+
207188
### Special thanks
208189

209190
This repo was originally created by [Thomas Nyholm from Happyr][forked-from].
210191

192+
[composer]: https://getcomposer.org/
193+
211194
[register-app]: https://www.linkedin.com/developers/apps
195+
212196
[api-doc-authentication]: https://learn.microsoft.com/en-us/linkedin/shared/authentication/authentication
197+
213198
[api-doc-core]: https://learn.microsoft.com/en-us/linkedin/shared/api-guide/concepts
199+
214200
[forked-from]: https://github.com/Happyr/LinkedIn-API-client

composer.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,15 @@
2222
],
2323
"require": {
2424
"php": "^7.2 || ^8.0",
25+
"ext-json": "*",
2526
"php-http/discovery": "^1.0",
26-
"php-http/httplug": "^1.0 || ^2.0",
27-
"php-http/message-factory": "^1.0",
28-
"psr/http-client-implementation": "^1.0"
27+
"psr/http-client-implementation": "*",
28+
"psr/http-factory-implementation": "*"
2929
},
3030
"require-dev": {
31-
"ext-json": "*",
31+
"guzzlehttp/guzzle": "^7.0",
3232
"illuminate/support": "^12.0",
33-
"mockery/mockery": "^1.0",
34-
"php-http/guzzle7-adapter": "^1.0"
33+
"mockery/mockery": "^1.0"
3534
},
3635
"autoload": {
3736
"psr-4": {
@@ -45,13 +44,14 @@
4544
},
4645
"config": {
4746
"allow-plugins": {
48-
"php-http/discovery": true
47+
"php-http/discovery": false
4948
}
5049
},
5150
"scripts": {
5251
"lint": "./tools/php-cs-fixer check",
5352
"lint-fix": "./tools/php-cs-fixer fix",
5453
"phpstan": "./tools/phpstan analyse --memory-limit=-1",
55-
"test": "./tools/phpunit"
54+
"test": "./tools/phpunit",
55+
"test-coverage": "XDEBUG_MODE=coverage ./tools/phpunit --coverage-text"
5656
}
5757
}

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
parameters:
22
level: 6
3+
treatPhpDocTypesAsCertain: false
34
paths:
45
- src

src/AuthenticatorInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function fetchNewAccessToken(LinkedInUrlGeneratorInterface $urlGenerator)
2424
/**
2525
* Generate a login url.
2626
*
27-
* @param array<mixed> $options
27+
* @param mixed[] $options
2828
*
2929
* @return string
3030
*/

src/Http/RequestManager.php

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
<?php declare(strict_types=1);
22
namespace Elnino\LinkedIn\Http;
33

4+
use function is_string;
45
use Elnino\LinkedIn\Exception\LinkedInTransferException;
5-
use Http\Client\Exception\TransferException;
6-
use Http\Client\HttpClient;
7-
use Http\Discovery\HttpClientDiscovery;
8-
use Http\Discovery\MessageFactoryDiscovery;
9-
use Http\Message\MessageFactory;
6+
use Http\Discovery\Psr17FactoryDiscovery;
7+
use Http\Discovery\Psr18ClientDiscovery;
8+
use Psr\Http\Client\ClientExceptionInterface;
9+
use Psr\Http\Client\ClientInterface;
10+
use Psr\Http\Message\RequestFactoryInterface;
11+
use Psr\Http\Message\RequestInterface;
12+
use Psr\Http\Message\ResponseInterface;
13+
use Psr\Http\Message\StreamFactoryInterface;
14+
use Psr\Http\Message\StreamInterface;
15+
use Psr\Http\Message\UriInterface;
16+
use RuntimeException;
1017

1118
/**
1219
* A class to create HTTP requests and to send them.
@@ -16,70 +23,64 @@
1623
class RequestManager implements RequestManagerInterface
1724
{
1825
/**
19-
* @var HttpClient
26+
* @var ClientInterface
2027
*/
2128
private $httpClient;
2229

2330
/**
24-
* @var MessageFactory
31+
* @var RequestFactoryInterface
2532
*/
26-
private $messageFactory;
33+
private $requestFactory;
2734

2835
/**
29-
* @inheritDoc
36+
* @var null|StreamFactoryInterface
3037
*/
31-
public function sendRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1')
32-
{
33-
$request = $this->getMessageFactory()->createRequest($method, $uri, $headers, $body, $protocolVersion);
38+
private $streamFactory;
3439

35-
try {
36-
return $this->getHttpClient()->sendRequest($request);
37-
} catch (TransferException $e) {
38-
throw new LinkedInTransferException('Error while requesting data from LinkedIn.com: ' . $e->getMessage(), $e->getCode(), $e);
39-
}
40+
public function __construct(?ClientInterface $httpClient = null, ?RequestFactoryInterface $requestFactory = null, ?StreamFactoryInterface $streamFactory = null)
41+
{
42+
$this->httpClient = $httpClient ?? Psr18ClientDiscovery::find();
43+
$this->requestFactory = $requestFactory ?? Psr17FactoryDiscovery::findRequestFactory();
44+
$this->streamFactory = $streamFactory ?? Psr17FactoryDiscovery::findStreamFactory();
4045
}
4146

4247
/**
4348
* @inheritDoc
4449
*/
45-
public function setHttpClient(HttpClient $httpClient)
50+
public function sendRequest($method, $uri, array $headers = [], $body = null): ResponseInterface
4651
{
47-
$this->httpClient = $httpClient;
48-
49-
return $this;
52+
try {
53+
return $this->httpClient->sendRequest(
54+
$this->createRequest($method, $uri, $headers, $body),
55+
);
56+
} catch (ClientExceptionInterface $e) {
57+
throw new LinkedInTransferException('Error while requesting data from LinkedIn.com: ' . $e->getMessage(), $e->getCode(), $e);
58+
}
5059
}
5160

5261
/**
53-
* @return RequestManager
62+
* @param string|UriInterface $uri
63+
* @param mixed[] $headers
64+
* @param null|StreamInterface|string $body
5465
*/
55-
public function setMessageFactory(MessageFactory $messageFactory)
66+
private function createRequest(string $method, $uri, array $headers = [], $body = null): RequestInterface
5667
{
57-
$this->messageFactory = $messageFactory;
68+
$request = $this->requestFactory->createRequest($method, $uri);
5869

59-
return $this;
60-
}
61-
62-
/**
63-
* @return HttpClient
64-
*/
65-
protected function getHttpClient()
66-
{
67-
if ($this->httpClient === null) {
68-
$this->httpClient = HttpClientDiscovery::find();
70+
foreach ($headers as $key => $value) {
71+
$request = $request->withHeader($key, $value);
6972
}
7073

71-
return $this->httpClient;
72-
}
74+
if (null !== $body && '' !== $body) {
75+
if (null === $this->streamFactory) {
76+
throw new RuntimeException('Cannot create request: A stream factory is required to create a request with a non-empty string body.');
77+
}
7378

74-
/**
75-
* @return MessageFactory
76-
*/
77-
private function getMessageFactory()
78-
{
79-
if ($this->messageFactory === null) {
80-
$this->messageFactory = MessageFactoryDiscovery::find();
79+
$request = $request->withBody(
80+
is_string($body) ? $this->streamFactory->createStream($body) : $body,
81+
);
8182
}
8283

83-
return $this->messageFactory;
84+
return $request;
8485
}
8586
}

0 commit comments

Comments
 (0)