CollaboratorGroupStructureResolverRegistryInitiated
Broadcast once when the collaborator group structure-resolver registry is first read. Listeners register their structure resolvers via addStrategy().
Last updated: June 7, 2026
CollaboratorGroupStructureResolverRegistryInitiated is broadcast exactly once, on the first read of the structure-resolver provider service. It’s the registration seam for any module that wants to add a new collaborator group structure (a layout that decides how members relate to each other, such as flat, linear chain, or parent-child). A structure registered here becomes selectable on a group without touching the Plus tier that owns the registry.
The event ID is collaborator_group_structure_resolver_registry_initiated, and its fully qualified class is Siren\Plus\Core\Groups\Structure\Events\CollaboratorGroupStructureResolverRegistryInitiated. 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 initialization so it is in place before that first read. A handler added after the first read misses the window and its structure never registers. See listeners, the events introduction, and the collaborator group events reference.
What does this event carry?
The event carries the CollaboratorGroupStructureResolverRegistry it populates and a PHPNomad\Di\Interfaces\InstanceProvider, both held as protected readonly constructor properties. It exposes two writers:
addStrategy(string $resolverClass): voidtakes aclass-string<CollaboratorGroupStructureResolver>. It stores a lazy factory, so the resolver class is only instantiated when something actually requests that structure. The registry key is$resolverClass::getId(), the structure id string such asflat,linearChain, orparentChild.deleteStrategy(string $id): voidremoves a registered resolver by its id.
Unlike the group and member field-resolver registries, which register a closure per field with addResolver, this registry registers a whole resolver class with addStrategy, keyed by the class’s own getId(). The id is read without instantiating the class, so getId() must be static. The resolver itself is built through the carried InstanceProvider the first time its structure is requested, so its constructor dependencies must be resolvable through Siren’s container. Registering a strategy whose getId() matches one already in the registry replaces it, so use a unique id unless you mean to override a built-in. Use deleteStrategy to remove or swap a strategy during this registration window. Removing a structure that existing groups are already configured to use leaves those groups unable to resolve their structure, so cascades bound to them fail closed.
use PHPNomad\Events\Interfaces\CanHandle;
use PHPNomad\Events\Interfaces\Event;
use Siren\Plus\Core\Groups\Structure\Events\CollaboratorGroupStructureResolverRegistryInitiated;
class RegisterMyStructureResolver implements CanHandle
{
public function handle(Event $event): void
{
if (!$event instanceof CollaboratorGroupStructureResolverRegistryInitiated) {
return;
}
// Pass the resolver class string; the registry keys it by
// MyStructureResolver::getId() and instantiates it lazily.
$event->addStrategy(MyStructureResolver::class);
}
}
How does it fit?
This is the standard three-tier registry pattern Siren uses for extension points: a registry (the structure-resolver store), an event (this one, broadcast on first read), and a provider service that lazy-builds the registry the first time a structure is requested. Plus registers only the flat structure resolver through RegisterPlusCollaboratorGroupStructureResolvers listening to this event.
The event is the seam the Pro tier uses to add the linear chain and parent-child structure resolvers. Pro’s RegisterProCollaboratorGroupStructureResolvers listens to the same event and calls addStrategy() for LinearChainCollaboratorGroupStructureResolver and ParentChildCollaboratorGroupStructureResolver. Because registration happens through the event rather than through edits to Plus, Pro adds its hierarchical structures with no Plus modifications required.
A structure resolver can also advertise walker capabilities, such as HAS_LAYER, through the HasProvidedWalkerCapabilities interface. Cascades require HAS_LAYER, so the linear chain and parent-child resolvers advertise it while flat does not. A custom structure that omits it is selectable on a group but cannot drive an upline or downline cascade, which is a quiet way to ship a structure that looks fine but never pays out a cascade. See custom structure resolvers for a full walkthrough of building and registering your own resolver, including which capabilities to declare.