Skip to content

Commit 9d92b58

Browse files
authored
Support multiple connections (#31)
* Support multiple connections * Store keys in DB * Remove tests for requests * Delete old concern * Upgrade guide * Default to DB store * Feedback
1 parent 20df543 commit 9d92b58

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+670
-577
lines changed

README.md

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ class Example
3535
$retrievedOrders[] = $order['increment_id'];
3636
}
3737
}
38+
39+
public function multipleConnections()
40+
{
41+
$this->magento->connection('connection_one')->get('products/1');
42+
$this->magento->connection('connection_two')->get('products/1');
43+
}
3844
}
3945

4046
```
@@ -68,6 +74,38 @@ Optionally, publish the configuration file of this package.
6874
php artisan vendor:publish --provider="JustBetter\MagentoClient\ServiceProvider" --tag=config
6975
```
7076

77+
## Multiple connections
78+
79+
This package supports connecting to multiple Magento instances.
80+
In the configuration file you will find an array with the connections where you can configure each connection.
81+
82+
```php
83+
'connection' => 'default',
84+
'connections' => [
85+
'default' => [
86+
/* Base URL of Magento, for example: https://magento.test */
87+
'base_url' => env('MAGENTO_BASE_URL'),
88+
89+
// Other settings
90+
],
91+
'another_connection' => [
92+
'base_url' => env('ANOTHER_MAGENTO_BASE_URL'),
93+
94+
// Other settings
95+
],
96+
],
97+
```
98+
99+
The `connection` setting sets which connection is used by default.
100+
You can switch connections by using the `connection` method on the client.
101+
102+
```php
103+
/** @var \JustBetter\MagentoClient\Client\Magento $client */
104+
$client = app(\JustBetter\MagentoClient\Client\Magento::class);
105+
106+
$client->connection('connection_one')->get('products');
107+
```
108+
71109
## Authentication
72110

73111
By default, this packages uses Bearer tokens to authenticate to Magento. Since Magento 2.4.4, this method of authentication requires additional configuration in Magento as [described here](https://developer.adobe.com/commerce/webapi/get-started/authentication/gs-authentication-token).
@@ -87,16 +125,22 @@ Note that you can also remove `MAGENTO_ACCESS_TOKEN` at this point, as it will b
87125
Next, open Magento and create a new integration. When configuring, supply a `Callback URL` and `Identity link URL`. If you have not made any changes to your configuration, these are the URLs:
88126

89127
```
90-
Callback URL: https://example.com/magento/oauth/callback
91-
Identity link URL: https://example.com/magento/oauth/identity
128+
Callback URL: https://example.com/magento/oauth/callback/{connection}
129+
Identity link URL: https://example.com/magento/oauth/identity/{connection}
92130
```
93131

94-
When creating the integration, Magento will send multiple tokens and secrets to your application via the `callback`-endpoint. This information will be saved in a JSON file, as configured in `magento.php`. Magento will redirect you to the `identity`-endpoint in order to activate the integration.
132+
`connection` is the key in your connections array in the configuration file.
133+
134+
When creating the integration, Magento will send multiple tokens and secrets to your application via the `callback`-endpoint. This information will be saved in the database, as configured in `magento.php`. You may adjust this to save the key in a JSON file or create your own implementation
135+
Magento will redirect you to the `identity`-endpoint in order to activate the integration.
95136

96137
For more information about OAuth 1.0 in Magento, please consult the [documentation](https://developer.adobe.com/commerce/webapi/get-started/authentication/gs-authentication-oauth).
97138

98139
#### Identity endpoint
99140

141+
> [!CAUTION]
142+
> Be sure to add your authentication middleware
143+
100144
Note that the `identity`-endpoint **does not** have any authentication or authorization middleware by default - you should add this in the configuration yourself. If you do not have any form of protection, anyone could change the tokens in your secret file.
101145

102146
It is recommended that only administrators of your application are allowed to access the identity endpoint.
@@ -142,11 +186,17 @@ $search = \JustBetter\MagentoClient\Query\SearchCriteria::make()
142186

143187
You can view more examples in [Magento's documentation](https://developer.adobe.com/commerce/webapi/rest/use-rest/performing-searches/).
144188

145-
### Pre defined requests (deprecated)
189+
### Connections
146190

147-
> Requests are deprecated as the `lazy` functionality has been made available in the client itself.
191+
You can connect to other connections using the `connection` method on the client.
148192

149-
This package comes bundled with a few predefined request so that you do not have to reinvent the wheel.
193+
```php
194+
/** @var \JustBetter\MagentoClient\Client\Magento $client */
195+
$client = app(\JustBetter\MagentoClient\Client\Magento::class);
196+
197+
$client->connection('connection_one')->get('products');
198+
$client->connection('connection_two')->get('products');
199+
```
150200

151201
### More Examples
152202

UPGRADE.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Upgrade guide
2+
3+
# 1.x to 2.x
4+
5+
2.x introduces support for multiple connections. To upgrade you must adjust your configuration file and OAuth urls.
6+
7+
## Configuration file
8+
9+
The configuration file has been changed to support multiple connections.
10+
It is recommended to overwrite the version from the package so that you are up to date.
11+
12+
The environment variables did not change.
13+
This means that if you have a single Magento connection you code will not break.
14+
15+
## OAuth
16+
17+
> [!NOTE]
18+
> This step is only required when using OAuth authentication
19+
20+
Reauthorize your Magento integration to create the record in your DB.
21+
22+
### URL
23+
24+
The OAuth URL's now require a connection parameter, if you have a single Magento instance the connection value is `default` by default.
25+
26+
```
27+
Callback URL: https://example.com/magento/oauth/callback/{connection}
28+
Identity link URL: https://example.com/magento/oauth/identity/{connection}
29+
```
30+
31+
### Key Location
32+
33+
OAuth keys are now stored in the database by default.
34+
If you prefer to store them on disk you can use the `\JustBetter\MagentoClient\OAuth\KeyStore\FileKeyStore` or implement your own keystore.
35+
36+
37+
## Testing
38+
39+
The `Magento::fake()` method has been altered to use the URL `magento` instead of `http://magento.test`. You should replace this in your tests.

config/magento.php

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,35 @@
22

33
return [
44

5-
/* Base URL of Magento, for example: https://magento.test */
6-
'base_url' => env('MAGENTO_BASE_URL'),
5+
'connection' => 'default',
76

8-
/* Base path, only modify if your API is not at /rest */
9-
'base_path' => env('MAGENTO_BASE_PATH', 'rest'),
7+
'connections' => [
8+
'default' => [
9+
/* Base URL of Magento, for example: https://magento.test */
10+
'base_url' => env('MAGENTO_BASE_URL'),
1011

11-
/* Store code, modify if you want to set a store by default. */
12-
'store_code' => env('MAGENTO_STORE_CODE', 'all'),
12+
/* Base path, only modify if your API is not at /rest */
13+
'base_path' => env('MAGENTO_BASE_PATH', 'rest'),
1314

14-
/* Modify if Magento has a new API version */
15-
'version' => env('MAGENTO_API_VERSION', 'V1'),
15+
/* Store code, modify if you want to set a store by default. */
16+
'store_code' => env('MAGENTO_STORE_CODE', 'all'),
1617

17-
/* Magento access token of an integration */
18-
'access_token' => env('MAGENTO_ACCESS_TOKEN'),
18+
/* Modify if Magento has a new API version */
19+
'version' => env('MAGENTO_API_VERSION', 'V1'),
1920

20-
/* Specify the timeout (in seconds) for the request. */
21-
'timeout' => 30,
21+
/* Magento access token of an integration */
22+
'access_token' => env('MAGENTO_ACCESS_TOKEN'),
2223

23-
/* Specify the connection timeout (in seconds) for the request. */
24-
'connect_timeout' => 10,
24+
/* Specify the timeout (in seconds) for the request. */
25+
'timeout' => 30,
2526

26-
/* Authentication method, choose either "oauth" or "token". */
27-
'authentication_method' => env('MAGENTO_AUTH_METHOD', 'token'),
27+
/* Specify the connection timeout (in seconds) for the request. */
28+
'connect_timeout' => 10,
29+
30+
/* Authentication method, choose either "oauth" or "token". */
31+
'authentication_method' => env('MAGENTO_AUTH_METHOD', 'token'),
32+
],
33+
],
2834

2935
/* OAuth configuration */
3036
'oauth' => [
@@ -37,17 +43,7 @@
3743
/* Prefix for the oauth routes. */
3844
'prefix' => 'magento/oauth',
3945

40-
/* File configuration */
41-
'file' => [
42-
43-
/* Disk to use. */
44-
'disk' => 'local',
45-
46-
/* File to store the credentials in. */
47-
'path' => 'secret/magento2_oauth.json',
48-
49-
/* Visibility for the secret file */
50-
'visibility' => 'private',
51-
],
46+
/* Class that manages how the keys are stored */
47+
'keystore' => \JustBetter\MagentoClient\OAuth\KeyStore\DatabaseKeyStore::class,
5248
],
5349
];
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up(): void
10+
{
11+
Schema::create('magento_oauth_keys', function (Blueprint $table): void {
12+
$table->id();
13+
$table->string('magento_connection')->index();
14+
15+
$table->json('keys');
16+
17+
$table->timestamps();
18+
});
19+
}
20+
21+
public function down(): void
22+
{
23+
Schema::dropIfExists('magento_oauth_keys');
24+
}
25+
};

routes/web.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
use Illuminate\Support\Facades\Route;
44
use JustBetter\MagentoClient\Http\Controllers\OAuthController;
55

6-
Route::post('callback', [OAuthController::class, 'callback'])
6+
Route::post('callback/{connection}', [OAuthController::class, 'callback'])
77
->name('magento.oauth.callback');
88

9-
Route::get('identity', [OAuthController::class, 'identity'])
9+
Route::get('identity/{connection}', [OAuthController::class, 'identity'])
1010
->middleware(config('magento.oauth.middleware'))
1111
->name('magento.oauth.identity');

src/Actions/AuthenticateRequest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88

99
class AuthenticateRequest implements AuthenticatesRequest
1010
{
11-
public function authenticate(PendingRequest $request): PendingRequest
11+
public function authenticate(PendingRequest $request, string $connection): PendingRequest
1212
{
1313
/** @var string $method */
14-
$method = config('magento.authentication_method');
14+
$method = config('magento.connections.'.$connection.'.authentication_method');
1515

1616
$auth = AuthenticationMethod::from($method);
1717

18-
return $auth->provider()->authenticate($request);
18+
return $auth->provider()->authenticate($request, $connection);
1919
}
2020

2121
public static function bind(): void

src/Actions/BuildRequest.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@ public function __construct(
1414
) {
1515
}
1616

17-
public function build(): PendingRequest
17+
public function build(string $connection): PendingRequest
1818
{
19-
$pendingRequest = Http::baseUrl(config('magento.base_url'))
20-
->timeout(config('magento.timeout'))
21-
->connectTimeout(config('magento.connect_timeout'))
19+
/** @var array $options */
20+
$options = config('magento.connections.'.$connection);
21+
22+
$pendingRequest = Http::baseUrl($options['base_url'])
23+
->timeout($options['timeout'])
24+
->connectTimeout($options['connect_timeout'])
2225
->acceptJson()
2326
->asJson();
2427

25-
return $this->request->authenticate($pendingRequest);
28+
return $this->request->authenticate($pendingRequest, $connection);
2629
}
2730

2831
public static function bind(): void

src/Actions/OAuth/ManageKeys.php

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/Actions/OAuth/RequestAccessToken.php

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,17 @@
33
namespace JustBetter\MagentoClient\Actions\OAuth;
44

55
use Illuminate\Support\Facades\Validator;
6-
use JustBetter\MagentoClient\Contracts\OAuth\ManagesKeys;
76
use JustBetter\MagentoClient\Contracts\OAuth\RequestsAccessToken;
87
use JustBetter\MagentoClient\OAuth\HmacSha256Signature;
8+
use JustBetter\MagentoClient\OAuth\KeyStore\KeyStore;
99
use JustBetter\MagentoClient\OAuth\MagentoServer;
1010
use League\OAuth1\Client\Credentials\ClientCredentials;
1111

1212
class RequestAccessToken implements RequestsAccessToken
1313
{
14-
public function __construct(
15-
protected ManagesKeys $keys
16-
) {
17-
}
18-
19-
public function request(string $key): void
14+
public function request(string $connection, string $key): void
2015
{
21-
$keys = $this->keys->get();
16+
$keys = KeyStore::instance()->get($connection);
2217

2318
$callback = $keys['callback'] ?? [];
2419

@@ -35,14 +30,16 @@ public function request(string $key): void
3530
$credentials = new ClientCredentials();
3631
$credentials->setIdentifier($callback['oauth_consumer_key']);
3732
$credentials->setSecret($callback['oauth_consumer_secret']);
38-
$credentials->setCallbackUri(route('magento.oauth.callback'));
33+
$credentials->setCallbackUri(route('magento.oauth.callback', ['connection' => $connection]));
3934

4035
/** @var MagentoServer $server */
4136
$server = app()->makeWith(MagentoServer::class, [
4237
'clientCredentials' => $credentials,
4338
'signature' => new HmacSha256Signature($credentials),
4439
]);
4540

41+
$server->connection = $connection;
42+
4643
$temporaryCredentials = $server->getTemporaryCredentials();
4744

4845
$tokenCredentials = $server->getTokenCredentials(
@@ -54,7 +51,8 @@ public function request(string $key): void
5451
$auth['access_token'] = $tokenCredentials->getIdentifier();
5552
$auth['access_token_secret'] = $tokenCredentials->getSecret();
5653

57-
$this->keys->set(
54+
KeyStore::instance()->set(
55+
$connection,
5856
array_merge($callback, $auth),
5957
);
6058
}

0 commit comments

Comments
 (0)