Skip to content

Commit fe63036

Browse files
committed
feat(zohoCliq): add DataCenter class for Zoho Cliq API integration
- Introduced a new DataCenter class to manage data center URLs for Zoho Cliq. - Implemented methods to retrieve base URLs for both API and OAuth based on the specified data center. - Utilized PHP 8.0 match expression for cleaner URL resolution. - Added exception handling for invalid data center inputs. Signed-off-by: guanguans <[email protected]>
1 parent 0836713 commit fe63036

File tree

7 files changed

+117
-37
lines changed

7 files changed

+117
-37
lines changed

ide.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2334,7 +2334,6 @@
23342334
"client_id",
23352335
"client_secret",
23362336
"code",
2337-
"data_center",
23382337
"grant_type",
23392338
"redirect_uri",
23402339
"refresh_token",

src/Foundation/Authenticators/UriTemplateAuthenticator.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function applyToRequest(RequestInterface $request): RequestInterface
4242
$this->uriFactory->createUri(
4343
UriTemplate::expand(urldecode((string) $request->getUri()), $this->variables),
4444
),
45+
$request->hasHeader('Host')
4546
);
4647
}
4748
}

src/Foundation/Authenticators/WebHookAuthenticator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ public function __construct(
3131

3232
public function applyToRequest(RequestInterface $request): RequestInterface
3333
{
34-
return $request->withUri($this->uriFactory->createUri($this->webHook));
34+
return $request->withUri($this->uriFactory->createUri($this->webHook), $request->hasHeader('Host'));
3535
}
3636
}

src/ZohoCliq/Authenticator.php

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,29 @@
4848
*/
4949
class Authenticator extends NullAuthenticator implements \Stringable
5050
{
51+
private DataCenter $dataCenter;
5152
private CacheInterface $cache;
5253
private string $cacheKey;
5354
private Client $client;
5455

56+
/**
57+
* @noinspection PhpDocSignatureInspection
58+
*
59+
* @param null|key-of<\Guanguans\Notify\ZohoCliq\DataCenter::BASE_URI_MAP> $dataCenter
60+
*/
5561
public function __construct(
5662
private string $clientId,
5763
#[\SensitiveParameter]
5864
private string $clientSecret,
65+
?string $dataCenter = null,
5966
?CacheInterface $cache = null,
6067
?string $cacheKey = null,
6168
?Client $client = null,
6269
) {
70+
$this->dataCenter = new DataCenter($dataCenter);
6371
$this->cache = $cache ?? new FileCache;
64-
$this->cacheKey = $cacheKey ?? "zoho_cliq.access_token.$clientId.$clientSecret";
65-
$this->client = $client ?? new Client;
72+
$this->cacheKey = $cacheKey ?? "zoho_cliq.access_token.$this->dataCenter.$clientId.$clientSecret";
73+
$this->client = ($client ?? new Client)->push($this->baseUriMiddleware($this->dataCenter->toOauthBaseUri()));
6674
}
6775

6876
/**
@@ -80,35 +88,20 @@ public function applyToMiddleware(callable $handler): callable
8088
{
8189
return array_reduce(
8290
[
83-
[$this, 'dataCenter'],
84-
[$this, 'retry'],
85-
[$this, 'authenticate'],
91+
$this->retryMiddleware(),
92+
$this->authMiddleware(),
93+
$this->baseUriMiddleware($this->dataCenter->toBaseUri()),
8694
],
8795
static fn (callable $handler, callable $next): callable => $next($handler),
8896
$handler,
8997
);
9098
}
9199

92-
/**
93-
* @todo
94-
*/
95-
private function dataCenter(callable $handler): callable
96-
{
97-
return $handler;
98-
}
99-
100-
private function authenticate(callable $handler): callable
101-
{
102-
return Middleware::mapRequest(
103-
fn (RequestInterface $request): RequestInterface => $request->withHeader('Authorization', "Bearer $this"),
104-
)($handler);
105-
}
106-
107100
/**
108101
* @see \GuzzleHttp\RetryMiddleware::onFulfilled()
109102
* @see \GuzzleHttp\RetryMiddleware::onRejected()
110103
*/
111-
private function retry(callable $handler): callable
104+
private function retryMiddleware(): callable
112105
{
113106
return Middleware::retry(
114107
function (int $retries, RequestInterface &$request, ?ResponseInterface $response = null): bool {
@@ -124,7 +117,31 @@ function (int $retries, RequestInterface &$request, ?ResponseInterface $response
124117

125118
return false;
126119
}
127-
)($handler);
120+
);
121+
}
122+
123+
private function authMiddleware(): callable
124+
{
125+
return Middleware::mapRequest(
126+
fn (RequestInterface $request): RequestInterface => $request->withHeader('Authorization', "Bearer $this"),
127+
);
128+
}
129+
130+
/**
131+
* @see \GuzzleHttp\Client::buildUri()
132+
* @see \GuzzleHttp\Client::requestAsync()
133+
* @see \GuzzleHttp\Client::sendAsync()
134+
*/
135+
private function baseUriMiddleware(string $baseUri): callable
136+
{
137+
$parsedBaseUri = parse_url($baseUri);
138+
139+
return Middleware::mapRequest(
140+
static fn (RequestInterface $request): RequestInterface => $request->withUri(
141+
$request->getUri()->withScheme($parsedBaseUri['scheme'])->withHost($parsedBaseUri['host']),
142+
$request->hasHeader('Host')
143+
),
144+
);
128145
}
129146

130147
/**
@@ -157,6 +174,10 @@ private function getToken(): string
157174
* "expires_in": 3600
158175
* }
159176
* ```
177+
*
178+
* ```json
179+
* {"error":"invalid_client_secret"}
180+
* ```
160181
*/
161182
private function refreshToken(): string
162183
{

src/ZohoCliq/Client.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,5 @@ class Client extends \Guanguans\Notify\Foundation\Client
2626
public function __construct(Authenticator $authenticator)
2727
{
2828
parent::__construct($authenticator);
29-
$this->baseUri('https://cliq.zoho.com/');
3029
}
3130
}

src/ZohoCliq/DataCenter.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2021-2025 guanguans<[email protected]>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*
11+
* @see https://github.com/guanguans/notify
12+
*/
13+
14+
namespace Guanguans\Notify\ZohoCliq;
15+
16+
use Guanguans\Notify\Foundation\Exceptions\InvalidArgumentException;
17+
18+
/**
19+
* @see https://www.zoho.com/cliq/help/restapi/v2/#cliq_rest_api
20+
* @see https://github.com/MarJose123/laravel-zoho-cliq-alert/blob/main/src/ZohoDataCenter.php
21+
*
22+
* @immutable
23+
*
24+
* @readonly
25+
*/
26+
class DataCenter implements \Stringable
27+
{
28+
public const AU = 'au';
29+
public const CA = 'ca';
30+
public const CN = 'cn';
31+
public const EU = 'eu';
32+
public const IN = 'in';
33+
public const JP = 'jp';
34+
public const SA = 'sa';
35+
public const UK = 'uk';
36+
public const US = 'us';
37+
private const BASE_URI_MAP = [
38+
self::AU => 'https://cliq.zoho.com.au',
39+
self::CA => 'https://cliq.zohocloud.ca',
40+
self::CN => 'https://cliq.zoho.com.cn',
41+
self::EU => 'https://cliq.zoho.eu',
42+
self::IN => 'https://cliq.zoho.in',
43+
self::JP => 'https://cliq.zoho.jp',
44+
self::SA => 'https://cliq.zoho.sa',
45+
self::UK => 'https://cliq.zoho.uk',
46+
self::US => 'https://cliq.zoho.com',
47+
];
48+
private string $value;
49+
50+
public function __construct(?string $value = null)
51+
{
52+
if (!isset(self::BASE_URI_MAP[$this->value = $value ?? self::US])) {
53+
throw new InvalidArgumentException("Invalid data center [$this->value].");
54+
}
55+
}
56+
57+
public function __toString(): string
58+
{
59+
return $this->value;
60+
}
61+
62+
public function toOauthBaseUri(): string
63+
{
64+
return str_replace('https://cliq.', 'https://accounts.', $this->toBaseUri());
65+
}
66+
67+
public function toBaseUri(): string
68+
{
69+
return self::BASE_URI_MAP[$this->value];
70+
}
71+
}

src/ZohoCliq/Messages/AccessTokenMessage.php

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515

1616
use Guanguans\Notify\Foundation\Concerns\AsFormParams;
1717
use Guanguans\Notify\Foundation\Message;
18-
use Guanguans\Notify\Foundation\Support\Arr;
1918

2019
/**
2120
* @method self clientId(mixed $clientId)
2221
* @method self clientSecret(mixed $clientSecret)
2322
* @method self code(mixed $code)
24-
* @method self dataCenter(mixed $dataCenter)
2523
* @method self grantType(mixed $grantType)
2624
* @method self redirectUri(mixed $redirectUri)
2725
* @method self refreshToken(mixed $refreshToken)
@@ -31,8 +29,6 @@ final class AccessTokenMessage extends Message // @internal
3129
{
3230
use AsFormParams;
3331
protected array $defined = [
34-
'data_center',
35-
3632
'client_id',
3733
'client_secret',
3834
'grant_type',
@@ -49,13 +45,6 @@ final class AccessTokenMessage extends Message // @internal
4945

5046
public function toHttpUri(): string
5147
{
52-
return 'https://accounts.zoho.com/oauth/v2/token';
53-
}
54-
55-
protected function toPayload(): array
56-
{
57-
return Arr::except(parent::toPayload(), [
58-
'data_center',
59-
]);
48+
return 'oauth/v2/token';
6049
}
6150
}

0 commit comments

Comments
 (0)