45
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Graph;
|
||||
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Client Microsoft Graph minimal (flux client credentials, permissions « application »).
|
||||
* Permissions requises, avec consentement administrateur : User.Read.All, GroupMember.Read.All.
|
||||
*/
|
||||
class GraphClient
|
||||
{
|
||||
public function __construct(private readonly string $tenantId) {}
|
||||
|
||||
public function token(): string
|
||||
{
|
||||
return Cache::remember("graph-token:{$this->tenantId}", now()->addMinutes(50), function () {
|
||||
$res = Http::asForm()->timeout(config('signature.graph.timeout'))
|
||||
->post("https://login.microsoftonline.com/{$this->tenantId}/oauth2/v2.0/token", [
|
||||
'client_id' => config('signature.graph.client_id'),
|
||||
'client_secret' => config('signature.graph.client_secret'),
|
||||
'scope' => 'https://graph.microsoft.com/.default',
|
||||
'grant_type' => 'client_credentials',
|
||||
]);
|
||||
if (! $res->successful()) {
|
||||
throw new RuntimeException('Jeton Graph refusé : '.$res->json('error_description', $res->body()));
|
||||
}
|
||||
|
||||
return $res->json('access_token');
|
||||
});
|
||||
}
|
||||
|
||||
/** GET sur une URL relative (/users…) ou absolue (@odata.nextLink). */
|
||||
public function get(string $url, array $headers = []): array
|
||||
{
|
||||
$full = str_starts_with($url, 'https://') ? $url : config('signature.graph.base_url').$url;
|
||||
|
||||
$res = Http::withToken($this->token())
|
||||
->withHeaders($headers)
|
||||
->timeout(config('signature.graph.timeout'))
|
||||
// Nouvel essai sur limitation (429) ou indisponibilité temporaire de Graph.
|
||||
->retry(3, 2000, fn ($e) => $e instanceof RequestException && in_array($e->response->status(), [429, 503, 504], true), throw: false)
|
||||
->get($full);
|
||||
|
||||
if (! $res->successful()) {
|
||||
throw new RuntimeException("Graph {$res->status()} sur {$url} : ".$res->body());
|
||||
}
|
||||
|
||||
return $res->json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcourt toutes les pages d'une collection.
|
||||
* Retourne [éléments, deltaLink|null].
|
||||
*/
|
||||
public function all(string $url, array $headers = []): array
|
||||
{
|
||||
$items = [];
|
||||
$delta = null;
|
||||
$next = $url;
|
||||
while ($next) {
|
||||
$page = $this->get($next, $headers);
|
||||
array_push($items, ...($page['value'] ?? []));
|
||||
$next = $page['@odata.nextLink'] ?? null;
|
||||
$delta = $page['@odata.deltaLink'] ?? $delta;
|
||||
}
|
||||
|
||||
return [$items, $delta];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user