Problem/Motivation

With "Restrict the amount of hierarchies per group to one" (limit_group_hierarchy_count) enabled, the parent field becomes effectively required once a group already has a root entity. This is enforced by GroupHierarchyParentConstraintValidator, which calls EntityHierarchyGroupHelper::currentHierarchyHasRoot().

However, the group-context branch of currentHierarchyHasRoot() queries group_relationship entities only by relationship type, not by the current group's gid. Since the relationship type (e.g. community-group_node-wiki_page) is shared across all groups of the same group type, a root entity in any group is detected as a root for every group.

Result: as soon as one group has a root hierarchy entity, you can no longer create the first (root) entity in any other group of the same type — the validator demands a parent, but the (correctly group-filtered) parent selection offers none. Deadlock. For closed groups this also leaks the existence of content across group boundaries.

Steps to reproduce

  1. Enable limit_group_hierarchy_count (and limit_group).
  2. In Group A, create the first hierarchy node (becomes root, no parent) — works.
  3. In Group B, try to create the first hierarchy node.
  4. Validation fails with the "root already exists, select a parent" violation, although Group B has no hierarchy content at all.

Root cause

src/EntityHierarchyGroupHelper.php, currentHierarchyHasRoot(), group branch:

$root_entity_relationships = $group_relationship_storage
  ->getQuery()
  ->condition('type', $group->getGroupType()->id() . '-group_' . $entity->getEntityTypeId() . '-' . $entity->getType())
  ->notExists('entity_id.entity:' . $entity->getEntityTypeId() . '.' . $field)
  ->accessCheck(TRUE)
  ->execute();

The query is missing a condition on the group id, so it returns root relationships from all groups of that type.

Proposed resolution

Scope the query to the current group:

$root_entity_relationships = $group_relationship_storage
  ->getQuery()
  ->condition('gid', $group_id)
  ->condition('type', $group->getGroupType()->id() . '-group_' . $entity->getEntityTypeId() . '-' . $entity->getType())
  ->notExists('entity_id.entity:' . $entity->getEntityTypeId() . '.' . $field)
  ->accessCheck(TRUE)
  ->execute();

Secondary note: accessCheck(TRUE) makes the existence check depend on the current user's access to other entities. For a pure "does a root already exist in this group" check, accessCheck(FALSE) would be more deterministic. The gid filter is the primary fix.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

atropoides created an issue. See original summary.

atropoides’s picture

Status: Active » Needs review
djanik’s picture

Good point, thanks!

  • 75f5718b committed on 1.0.x
    #3593197 - Filter root-existence check by current group gid
    
atropoides’s picture

Status: Needs review » Reviewed & tested by the community
atropoides’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.