SU-HKKU/cardinal_service_profile

View on GitHub
modules/cardinal_service_rest/src/Plugin/rest/resource/TermsUsedResource.php

Summary

Maintainability
A
0 mins
Test Coverage
A
95%
<?php

namespace Drupal\cardinal_service_rest\Plugin\rest\resource;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\FieldConfigInterface;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\taxonomy\TermInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Rest endpoint to provide data about what entities are tagged with terms.
 *
 * @RestResource(
 *   id = "terms_used_resource",
 *   label = @Translation("Terms In Use Resource"),
 *   uri_paths = {
 *     "canonical" = "/api/terms-used/{node_type}"
 *   }
 * )
 */
class TermsUsedResource extends ResourceBase {

  const ENTITY_TYPE = 'node';

  /**
   * Entity Type manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Entity field manager service.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $fieldManager;

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->getParameter('serializer.formats'),
      $container->get('logger.factory')->get('rest'),
      $container->get('entity_type.manager'),
      $container->get('entity_field.manager')
    );
  }

  /**
   * {@inheritDoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, EntityTypeManagerInterface $entityTypeManager, EntityFieldManagerInterface $field_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
    $this->entityTypeManager = $entityTypeManager;
    $this->fieldManager = $field_manager;
  }

  /**
   * {@inheritDoc}
   */
  public function permissions() {
    return [];
  }

  /**
   * Get request on the rest endpoint.
   *
   * @param string $node_type
   *   Node type bundle id.
   * @param bool $include_children
   *   If the data should include all children terms as well.
   *
   * @return \Drupal\rest\ResourceResponse
   *   Rest response.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function get($node_type, $include_children = TRUE) {
    $data = [];

    $fields = $this->fieldManager->getFieldDefinitions(self::ENTITY_TYPE, $node_type);
    foreach ($fields as $field_name => $field_definition) {
      if (
        $field_definition instanceof FieldConfig &&
        $field_definition->getType() == 'entity_reference' &&
        $field_definition->getSetting('handler') == 'default:taxonomy_term'
      ) {
        $data[$field_name] = $this->getFieldTermsData($field_definition, $include_children);
      }
    }

    $data = array_filter($data);

    $response = new ResourceResponse();
    $response->setContent(json_encode($data));
    $response->addCacheableDependency($data);
    $response->addCacheableDependency(CacheableMetadata::createFromRenderArray([
      '#cache' => ['tags' => ['api:opportunities']],
    ]));

    return $response;
  }

  /**
   * Get the available taxonomy terms with references to the entity using it.
   *
   * @param \Drupal\field\FieldConfigInterface $field
   *   Taxonomy field config entity.
   * @param bool $include_children
   *   If the data should include all children terms as well.
   *
   * @return array
   *   Array of structured term data.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getFieldTermsData(FieldConfigInterface $field, $include_children = FALSE) {
    $term_storage = $this->entityTypeManager->getStorage('taxonomy_term');
    $node_storage = $this->entityTypeManager->getStorage('node');

    $data = [];
    $handler_settings = $field->getSetting('handler_settings');
    $vid = reset($handler_settings['target_bundles']);

    foreach ($term_storage->loadByProperties([
      'vid' => $vid,
      'status' => 1,
    ]) as $term) {
      $term_ids = $include_children ? $this->getChildrenIds($term) : [$term->id()];

      $query = $node_storage->getQuery()
        ->condition('status', 1)
        ->condition('type', $field->getTargetBundle())
        ->condition($field->getName(), $term_ids, 'IN');

      if ($field->getTargetBundle() == 'su_spotlight') {
        $query->condition('body', '', '!=');
      }

      $nodes = $query->accessCheck(FALSE)
        ->execute();

      if ($nodes) {
        $data[] = [
          'id' => $term->id(),
          'label' => $term->label(),
          'items' => array_values($nodes),
        ];
      }
    }

    uasort($data, function ($item_a, $item_b) {
      return count($item_a['items']) > count($item_b['items']) ? -1 : 1;
    });
    return array_values($data);
  }

  /**
   * Get an array of term ids with all children terms under it.
   *
   * @param \Drupal\taxonomy\TermInterface $term
   *   Parent taxonomy term.
   *
   * @return array
   *   Array of taxonomy term ids.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getChildrenIds(TermInterface $term) {
    $term_ids = [$term->id()];
    $child_terms = $this->entityTypeManager->getStorage('taxonomy_term')
      ->loadByProperties(['parent' => $term->id()]);
    foreach ($child_terms as $child_term) {
      $term_ids[] = $child_term->id();
      $term_ids[] = $this->getChildrenIds($child_term);
    }
    // Flatten the array.
    $term_ids = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($term_ids)), FALSE);
    // Remove duplicates.
    return array_values(array_unique($term_ids));
  }

}