public function isGrantedForRoles(array $roles, $privilegeType, $subject, &$reason = '')
    {
        $availablePrivileges = array_reduce($roles, $this->getPrivilegeByTypeReducer($privilegeType), []);
        $effectivePrivileges = array_filter($availablePrivileges, $this->getPrivilegeSubjectFilter($subject));
        /** @var PrivilegePermissionResult $result */
        $result = array_reduce($effectivePrivileges, [$this, 'applyPrivilegeToResult'], new PrivilegePermissionResult());

        $effectivePrivilegeIdentifiersWithPermission = $result->getEffectivePrivilegeIdentifiersWithPermission();
        if ($effectivePrivilegeIdentifiersWithPermission === []) {
            $reason = sprintf('No privilege of type "%s" matched.', $privilegeType);
            return true;
        }

        $reason = sprintf('Evaluated following %d privilege target(s):' . chr(10) . '%s' . chr(10) . '(%d granted, %d denied, %d abstained)',
            count($effectivePrivilegeIdentifiersWithPermission),
            implode(chr(10), $effectivePrivilegeIdentifiersWithPermission),
            $result->getGrants(),
            $result->getDenies(),
            $result->getAbstains()
        );

        if ($result->getDenies() > 0) {
            return false;
        }
        if ($result->getGrants() > 0) {
            return true;
        }

        return false;
    }