, failures: array} */ public function fetchAll(Tenant $tenant, string $foundationType): array { $resource = $this->contracts->resourcePath($foundationType); if (! $resource) { return [ 'items' => [], 'failures' => [[ 'foundation_type' => $foundationType, 'reason' => 'Graph contract resource missing for foundation type.', 'status' => null, ]], ]; } $contract = $this->contracts->get($foundationType); $query = []; if (! empty($contract['allowed_select']) && is_array($contract['allowed_select'])) { $query['$select'] = $contract['allowed_select']; } $sanitized = $this->contracts->sanitizeQuery($foundationType, $query); $options = $tenant->graphOptions(); $items = []; $failures = []; $nextPath = $resource; $useQuery = $sanitized['query'] ?? []; while ($nextPath) { $response = $this->graphClient->request('GET', $nextPath, $options + [ 'query' => $useQuery, ]); if ($response->failed()) { $failures[] = [ 'foundation_type' => $foundationType, 'reason' => $response->meta['error_message'] ?? $response->warnings[0] ?? 'Graph request failed.', 'status' => $response->status, ]; break; } $data = $response->data; $pageItems = $data['value'] ?? (is_array($data) ? $data : []); foreach ($pageItems as $item) { if (! is_array($item)) { continue; } $sourceId = $item['id'] ?? null; if (! is_string($sourceId) || $sourceId === '') { continue; } $displayName = $item['displayName'] ?? $item['name'] ?? null; $items[] = [ 'source_id' => $sourceId, 'display_name' => is_string($displayName) ? $displayName : null, 'payload' => $item, 'metadata' => [ 'displayName' => is_string($displayName) ? $displayName : null, 'kind' => $foundationType, 'graph' => [ 'resource' => $resource, 'apiVersion' => config('graph.version', 'beta'), ], ], ]; } $nextLink = $data['@odata.nextLink'] ?? null; if (! $nextLink) { break; } $nextPath = $this->stripGraphBaseUrl((string) $nextLink); $useQuery = []; } return [ 'items' => $items, 'failures' => $failures, ]; } private function stripGraphBaseUrl(string $nextLink): string { $base = rtrim(config('graph.base_url', 'https://graph.microsoft.com'), '/') .'/'.trim(config('graph.version', 'beta'), '/'); if (str_starts_with($nextLink, $base)) { return ltrim(substr($nextLink, strlen($base)), '/'); } return ltrim($nextLink, '/'); } }