@@ -61,48 +61,50 @@ The store interface is minimal:
6161interface EntityCollectionStoreInterface
6262{
6363 /**
64- * Persist discovered entity IDs for a given Trust Anchor.
64+ * Persist discovered entities for a given Trust Anchor.
6565 */
66- public function storeEntityIds (string $trustAnchorId, array $entityIds , int $ttl): void;
66+ public function store (string $trustAnchorId, array $entities , int $ttl): void;
6767
6868 /**
69- * Retrieve previously discovered entity IDs .
69+ * Retrieve previously discovered entities .
7070 * Return null when not found or expired.
7171 */
72- public function getEntityIds (string $trustAnchorId): ?array;
72+ public function get (string $trustAnchorId): ?array;
7373
7474 /**
75- * Remove stored entity IDs (for force re-discovery).
75+ * Remove stored entities (for force re-discovery).
7676 */
77- public function clearEntityIds (string $trustAnchorId): void;
77+ public function clear (string $trustAnchorId): void;
7878}
7979```
8080
81- > ** Note** : The store tracks only the list of entity IDs per Trust Anchor, not
82- > the Entity Configurations themselves. Entity Configurations are fetched
83- > dynamically through ` EntityStatementFetcher::fromCacheOrWellKnownEndpoint() ` ,
84- > which already handles JWS-level caching and respects expiry.
81+ > ** Note** : The store tracks the JWT payload arrays per Trust Anchor.
82+ > Entity Configurations are fetched dynamically through ` EntityStatementFetcher::fromCacheOrWellKnownEndpoint() `
83+ > during the traversal process, which handles JWS-level caching and respects expiry.
8584
8685## Federation Discovery
8786
8887Federation Discovery performs a top-down traversal of the federation hierarchy.
8988Starting from a Trust Anchor, it follows ` federation_list_endpoint ` links on
9089each entity to collect all subordinate entity IDs recursively.
9190
92- ### Discovering Entity IDs
91+ ### Discovering Entities
9392
9493``` php
9594/** @var \SimpleSAML\OpenID\Federation $federationTools */
9695
9796$trustAnchorId = 'https://trust-anchor.example.org/';
9897
9998try {
100- // Discover all entity IDs in the federation.
101- $entityIds = $federationTools->federationDiscovery()
102- ->discoverEntities ($trustAnchorId);
99+ // Discover all entities (ID -> payload map) in the federation.
100+ $entities = $federationTools->federationDiscovery()
101+ ->discover ($trustAnchorId);
103102
104- // $entityIds is an array of entity ID strings, e.g.:
105- // ['https://trust-anchor.example.org/', 'https://intermediate.example.org/', ...]
103+ // $entities is an array keyed by entity ID, where values are JWT payload arrays:
104+ // [
105+ // 'https://trust-anchor.example.org/' => ['iss' => '...', 'metadata' => [...]],
106+ // ...
107+ // ]
106108} catch (\Throwable $exception) {
107109 $logger->error('Federation discovery failed: ' . $exception->getMessage());
108110}
@@ -115,63 +117,46 @@ The discovery algorithm:
1151173 . Calls the subordinate listing endpoint to get immediate subordinate IDs.
1161184 . For each subordinate, fetches its Entity Configuration and, if it has its own
117119 ` federation_list_endpoint ` , recurses (up to ` maxDiscoveryDepth ` ).
118- 5 . Deduplicates all collected entity IDs .
119- 6 . Persists the ID list in the store with a TTL based on the Trust Anchor's
120+ 5 . Deduplicates all collected entities .
121+ 6 . Persists the entity payloads in the store with a TTL based on the Trust Anchor's
120122 expiry and the configured ` maxCacheDuration ` .
121123
124+ If you only need the list of entity IDs without their payloads, use the convenience method:
125+
126+ ``` php
127+ $entityIds = $federationTools->federationDiscovery()
128+ ->discoverEntityIds($trustAnchorId);
129+ ```
130+
122131### Applying Filters During Discovery
123132
124133You can pass filter parameters (e.g. ` entity_type ` ) to the subordinate listing
125134endpoint:
126135
127136``` php
128- $entityIds = $federationTools->federationDiscovery()
129- ->discoverEntities (
137+ $entities = $federationTools->federationDiscovery()
138+ ->discover (
130139 $trustAnchorId,
131140 filters: ['entity_type' => 'openid_relying_party'],
132141 );
133142```
134143
135- ### Discovering and Fetching Entity Configurations
136-
137- The convenience method ` discoverAndFetch() ` performs discovery and then fetches
138- the Entity Configuration for each discovered entity:
139-
140- ``` php
141- try {
142- // Returns array<string , EntityStatement > keyed by entity ID.
143- $entities = $federationTools->federationDiscovery()
144- ->discoverAndFetch($trustAnchorId);
145-
146- foreach ($entities as $entityId => $entityStatement) {
147- $metadata = $entityStatement->getMetadata();
148- // ...
149- }
150- } catch (\Throwable $exception) {
151- $logger->error('Discovery failed: ' . $exception->getMessage());
152- }
153- ```
154-
155- > ** Note** : Entity Configurations are fetched through the existing
156- > ` EntityStatementFetcher ` , which caches JWS at the network level. If a cached
157- > configuration has expired, a fresh one is fetched automatically.
158-
159144### Periodic Refresh (Cron / Background Jobs)
160145
161- Use the ` forceRefresh ` parameter to clear the stored entity ID list and
146+ Use the ` forceRefresh ` parameter to clear the stored entities and
162147re-traverse the federation. This is the intended pattern for cron or background
163148refresh jobs:
164149
165150``` php
166151// In a scheduled task / cron job:
167152$federationTools->federationDiscovery()
168- ->discoverAndFetch ($trustAnchorId, forceRefresh: true);
153+ ->discover ($trustAnchorId, forceRefresh: true);
169154```
170155
171156When ` forceRefresh ` is ` true ` :
172157
173158- The full federation traversal is re-executed.
174- - The new entity ID list is stored.
159+ - The new entity payload map is stored.
175160- Entity Configurations that haven't expired in the JWS cache are served from
176161 cache; only stale or new ones trigger network requests.
177162
@@ -309,7 +294,7 @@ use SimpleSAML\OpenID\Federation\EntityCollection;
309294
310295// Prepare a collection from discovery or any other source.
311296$entities = $federationTools->federationDiscovery()
312- ->discoverAndFetch ($trustAnchorId);
297+ ->discover ($trustAnchorId);
313298$collection = new EntityCollection($entities);
314299
315300// Filter by entity type and text query.
@@ -321,7 +306,7 @@ $filtered = $federationTools->entityCollectionFilter()->filter(
321306 ],
322307);
323308
324- // $filtered is array<string , EntityStatement > keyed by entity ID.
309+ // $filtered is array<string , array < string, mixed > > keyed by entity ID.
325310```
326311
327312#### EntityCollectionSorter
@@ -333,7 +318,7 @@ Sorts entities by a metadata claim value:
333318
334319// Sort by display_name under the federation_entity metadata.
335320$sorted = $federationTools->entityCollectionSorter()->sortByMetadataClaim(
336- $filtered, // array<string , EntityStatement >
321+ $filtered, // array<string , array < string, mixed > >
337322 ['federation_entity', 'display_name'],
338323 'asc',
339324);
@@ -356,7 +341,7 @@ Slices a pre-sorted result set into a page with an opaque cursor:
356341/** @var \SimpleSAML\OpenID\Federation $federationTools */
357342
358343$paginated = $federationTools->entityCollectionPaginator()->paginate(
359- $sorted, // Pre-sorted array<string , EntityStatement |EntityCollectionEntry >
344+ $sorted, // Pre-sorted array<string , array < string, mixed > |EntityCollectionEntry>
360345 20, // Limit (page size)
361346 null, // Cursor from a previous response's 'next' value, or null
362347);
0 commit comments