*/ private array $sources = []; public function add(RoleSource ...$sources): self { foreach ($sources as $source) { $this->sources[] = $source; } return $this; } /** * Everything a merchant may choose, as slug => the site's own word for it. * * @return array */ public function offered(): array { $offered = []; foreach ($this->sources as $source) { // `+` rather than `array_merge`, so the FIRST source to offer a // slug keeps its word for it. Which is arbitrary between two // adapters and is not arbitrary between an adapter and WordPress: // free registers `WpRoleSource` at boot, so `subscriber` reads as // WordPress's role however many plugins later claim the word. $offered += $source->offered(); } return $offered; } /** * What the CURRENT visitor holds, across every source. * * @return list */ public function held(): array { $held = []; foreach ($this->sources as $source) { foreach ($source->held() as $role) { $held[] = $role; } } return array_values(array_unique($held)); } }