You are here

public function EntityHierarchy::getTree in Entity Reference Hierarchy 3.x

Same name and namespace in other branches
  1. 8.2 modules/entity_hierarchy_workbench_access/src/Plugin/AccessControlHierarchy/EntityHierarchy.php \Drupal\entity_hierarchy_workbench_access\Plugin\AccessControlHierarchy\EntityHierarchy::getTree()

File

modules/entity_hierarchy_workbench_access/src/Plugin/AccessControlHierarchy/EntityHierarchy.php, line 131

Class

EntityHierarchy
Defines a hierarchy based on an entity hierarchy field.

Namespace

Drupal\entity_hierarchy_workbench_access\Plugin\AccessControlHierarchy

Code

public function getTree() {
  if (!isset($this->tree)) {
    if ($data = $this->cacheBackend
      ->get(self::CACHE_ID)) {
      $this->tree = $data->data;
      return $this->tree;
    }
    $entity_type_id = $this->pluginDefinition['entity'];
    $entity_type = $this->entityTypeManager
      ->getDefinition($entity_type_id);
    $field_name = $this->pluginDefinition['field_name'];

    /** @var \PNX\NestedSet\Storage\DbalNestedSet $tree_storage */
    $tree_storage = $this->nestedSetStorageFactory
      ->get($field_name, $entity_type_id);
    $entityStorage = $this->entityTypeManager
      ->getStorage($entity_type_id);
    $query = $entityStorage
      ->getQuery();
    $tree = [];
    $or = $query
      ->orConditionGroup();
    $boolean_fields = $this->configuration['boolean_fields'];
    foreach ($boolean_fields as $boolean_field) {
      $or
        ->condition($boolean_field, 1);
      $tree[$boolean_field] = [];
    }
    if ($boolean_fields) {
      $query
        ->condition($or);
    }
    $valid_ids = $query
      ->execute();
    if (!$valid_ids) {
      return $tree;
    }
    $aggregate = $entityStorage
      ->getAggregateQuery();
    $aggregate
      ->groupBy($entity_type
      ->getKey('label'))
      ->groupBy($entity_type
      ->getKey('id'));
    foreach ($boolean_fields as $boolean_field) {
      $aggregate
        ->groupBy($boolean_field);
    }
    $aggregate
      ->condition($entity_type
      ->getKey('id'), $valid_ids, 'IN');
    $details = $aggregate
      ->execute();
    $boolean_parents = array_combine(array_column($details, $entity_type
      ->getKey('id')), array_map(function ($item) use ($entity_type) {

      // Remove the label/id fields.
      unset($item[$entity_type
        ->getKey('label')], $item[$entity_type
        ->getKey('id')]);

      // Return just the boolean fields that were checked.
      return array_keys(array_filter($item));
    }, $details));
    $entities = $entityStorage
      ->loadMultiple($valid_ids);
    $tags = $entityStorage
      ->getEntityType()
      ->getListCacheTags();
    foreach ($entities as $id => $entity) {

      /** @var \PNX\NestedSet\Node $node */
      $key = $this->keyFactory
        ->fromEntity($entity);
      $node = $tree_storage
        ->getNode($key);
      if (!$node) {
        continue;
      }
      $tags = array_merge($tags, $entities[$id]
        ->getCacheTags());
      foreach ($boolean_parents[$id] as $parent) {
        $cid = sprintf('%s:%s', self::CACHE_ID, $id);
        if ($entry = $this->cacheBackend
          ->get($cid)) {
          $tree[$parent][$id] = $entry->data;

          // Cache hit.
          continue;
        }
        $entry_tags = [];
        $entry = [
          'label' => $this
            ->generateEntityLabelWithAncestry($entity, $tree_storage, $entity_type_id, $entry_tags),
          'depth' => $node
            ->getDepth(),
          'parents' => [],
          'weight' => $node
            ->getLeft(),
          'description' => '',
        ];
        $tree[$parent][$id] = $entry;
        $this->cacheBackend
          ->set($cid, $entry, Cache::PERMANENT, $entry_tags);
        $tags = array_merge($tags, $entry_tags);
      }
    }
    foreach (array_keys($tree) as $parent) {
      uasort($tree[$parent], function (array $a, array $b) {

        // @todo Replace this with null coalesce and spaceship operator when
        // we only support PHP 7.0 or greater.
        $a_weight = 0;
        $b_weight = 0;
        if (isset($a['weight'])) {
          $a_weight = $a['weight'];
        }
        if (isset($b['weight'])) {
          $b_weight = $b['weight'];
        }
        if ($a_weight < $b_weight) {
          return -1;
        }
        if ($a_weight > $b_weight) {
          return 1;
        }
        return 0;
      });
    }
    $this->tree = $tree;
    $this->cacheBackend
      ->set(self::CACHE_ID, $tree, Cache::PERMANENT, array_unique($tags));
  }
  return $this->tree;
}