security = $security; $this->helper = $voterHelperFactory ->generate(self::class) ->addCheckFor(Center::class, [self::STATS]) ->build(); } public function getRoles(): array { return [self::STATS]; } public function getRolesWithHierarchy(): array { return ['Household' => $this->getRoles()]; } public function getRolesWithoutScope(): array { return $this->getRoles(); } protected function supports($attribute, $subject) { return ($subject instanceof Household && in_array($attribute, self::ALL, true)) || $this->helper->supports($attribute, $subject); } protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool { switch ($attribute) { case self::SEE: return $this->checkAssociatedMembersRole($subject, PersonVoter::SEE); case self::EDIT: return $this->checkAssociatedMembersRole($subject, PersonVoter::UPDATE); case self::STATS: return $this->voteOnAttribute($attribute, $subject, $token); default: throw new UnexpectedValueException('attribute not supported'); } } private function checkAssociatedMembersRole(Household $household, string $attribute): bool { foreach ($household->getCurrentMembers()->map(static fn (HouseholdMember $member) => $member->getPerson()) as $person) { if ($this->security->isGranted($attribute, $person)) { return true; } } return false; } }