Siren

CollaboratorGroupResolverRegistryInitiated

Broadcast once when the CollaboratorGroup field-resolver registry is first read. Listeners register per-field getter closures.

Last updated: June 3, 2026

CollaboratorGroupResolverRegistryInitiated is broadcast exactly once, on the first read of the CollaboratorGroup field-resolver registry. It’s the registration seam for any module that wants to expose a new field on the CollaboratorGroup resource. The field becomes part of the API response and the admin list view without touching the core Plus code.

The event ID is collaborator_group_resolver_registry_initiated, and its fully qualified class is Siren\Plus\Core\Groups\Events\CollaboratorGroupResolverRegistryInitiated. To run code when it fires, register a handler with Siren’s event system. Because the registry is built exactly once on first read, register your handler during plugin initialization, the same way the core resolvers are wired, so it is in place before that first read. A handler added after the first read misses the window and its field never appears. See listeners, the events introduction, and the collaborator group events reference.

What does this event carry?

The event extends the framework’s FieldResolverRegistryInitiatedEvent abstract and exposes one writer: addResolver(string $field, callable $resolver). The resolver is a closure that receives the CollaboratorGroup model and returns whatever value that field should expose.

use PHPNomad\Events\Interfaces\CanHandle;
use PHPNomad\Events\Interfaces\Event;
use Siren\Plus\Core\Groups\Events\CollaboratorGroupResolverRegistryInitiated;
use Siren\Plus\Core\Groups\Models\CollaboratorGroup;

class RegisterMemberCountResolver implements CanHandle
{
    public function handle(Event $event): void
    {
        if (!$event instanceof CollaboratorGroupResolverRegistryInitiated) {
            return;
        }

        $event->addResolver('memberCount', function (CollaboratorGroup $group) {
            // Return whatever derived value this field should expose
            return 0;
        });
    }
}

How does it fit?

This is the standard three-tier registry pattern Siren uses for extension points: a registry (the field-resolver store), an event (this one, broadcast on first read), and a provider service that lazy-builds the registry when something asks for a field. The core resolvers (id, name, description, structure) are registered the same way, through RegisterCoreCollaboratorGroupResolvers listening to this event. Higher tiers and third-party integrations follow the same pattern to add their own fields. The per-member rows have their own field-resolver registry with the same shape, and custom structure resolvers wire structures the same way.

A resolver runs once per group row on every list request, so keep it cheap. The memberCount example above would query the member datastore per group, which turns a list of groups into an N+1 query, so cache or batch that kind of lookup. Field names are unique in the registry, so registering a resolver for a name that already exists (a core field like name) replaces it. Use a distinct name unless you mean to override, and return JSON-friendly data, since the value is serialized onto the API row and the admin list.