contracts->get($policyType); $listPathTemplate = $contract['assignments_list_path'] ?? null; $resource = $contract['resource'] ?? null; $requestOptions = array_merge($options, ['tenant' => $tenantId]); // Try primary endpoint $assignments = $this->fetchPrimary($listPathTemplate, $policyId, $requestOptions); if (! empty($assignments)) { Log::debug('Fetched assignments via primary endpoint', [ 'tenant_id' => $tenantId, 'policy_type' => $policyType, 'policy_id' => $policyId, 'count' => count($assignments), ]); return $assignments; } // Try fallback with $expand Log::debug('Primary endpoint returned empty, trying fallback', [ 'tenant_id' => $tenantId, 'policy_type' => $policyType, 'policy_id' => $policyId, ]); if (! is_string($resource) || $resource === '') { Log::debug('Assignments resource not configured for policy type', [ 'tenant_id' => $tenantId, 'policy_type' => $policyType, 'policy_id' => $policyId, ]); return []; } $assignments = $this->fetchWithExpand($resource, $policyId, $requestOptions); if (! empty($assignments)) { Log::debug('Fetched assignments via fallback endpoint', [ 'tenant_id' => $tenantId, 'policy_type' => $policyType, 'policy_id' => $policyId, 'count' => count($assignments), ]); return $assignments; } // Both methods returned empty Log::debug('No assignments found for policy', [ 'tenant_id' => $tenantId, 'policy_type' => $policyType, 'policy_id' => $policyId, ]); return []; } catch (GraphException $e) { Log::warning('Failed to fetch assignments', [ 'tenant_id' => $tenantId, 'policy_type' => $policyType, 'policy_id' => $policyId, 'error' => $e->getMessage(), 'context' => $e->context, ]); return []; } } /** * Fetch assignments using primary endpoint. */ private function fetchPrimary(?string $listPathTemplate, string $policyId, array $options): array { if (! is_string($listPathTemplate) || $listPathTemplate === '') { return []; } $path = $this->resolvePath($listPathTemplate, $policyId); if ($path === null) { return []; } $response = $this->graphClient->request('GET', $path, $options); return $response->data['value'] ?? []; } /** * Fetch assignments using $expand fallback. */ private function fetchWithExpand(string $resource, string $policyId, array $options): array { $path = $resource; $params = [ '$expand' => 'assignments', '$filter' => "id eq '{$policyId}'", ]; $response = $this->graphClient->request('GET', $path, array_merge($options, [ 'query' => $params, ])); $policies = $response->data['value'] ?? []; if (empty($policies)) { return []; } return $policies[0]['assignments'] ?? []; } private function resolvePath(string $template, string $policyId): ?string { if ($template === '') { return null; } return str_replace('{id}', urlencode($policyId), $template); } }