Skip to content
Snippets Groups Projects
Forked from project / hierarchy_manager
58 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
HmTaxonomyController.php 7.05 KiB
<?php

namespace Drupal\hierarchy_manager\Controller;

use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\taxonomy\VocabularyInterface;
use Drupal\taxonomy\Entity\Term;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;

/**
 * Taxononmy controller class.
 */
class HmTaxonomyController extends ControllerBase {

  /**
   * CSRF Token.
   *
   * @var \Drupal\Core\Access\CsrfTokenGenerator
   */
  protected $csrfToken;

  /**
   * The term storage handler.
   *
   * @var \Drupal\taxonomy\TermStorageInterface
   */
  protected $storageController;

  /**
   * Display plugin manager.
   *
   * @var \Drupal\hierarchy_manager\Plugin\HmDisplayPluginInterface
   */
  protected $displayManager;

  /**
   * Setup plugin manager.
   *
   * @var \Drupal\hierarchy_manager\Plugin\HmSetupPluginManager
   */
  protected $setupManager;

  /**
   * {@inheritdoc}
   */
  public function __construct(CsrfTokenGenerator $csrfToken, EntityTypeManagerInterface $entity_type_manager, $display_manager, $setup_manager) {

    $this->csrfToken = $csrfToken;
    $this->entityTypeManager = $entity_type_manager;
    $this->storageController = $entity_type_manager->getStorage('taxonomy_term');
    $this->displayManager = $display_manager;
    $this->setupManager = $setup_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
        $container->get('csrf_token'),
        $container->get('entity_type.manager'),
        $container->get('plugin.manager.hm.display_plugin'),
        $container->get('plugin.manager.hm.hmsetup')
        );
  }

  /**
   * Callback for taxonomy tree json.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   Http request object.
   * @param string $vid
   *   Vocabulary ID.
   */
  public function taxonomyTreeJson(Request $request, string $vid) {
    // Access token.
    $token = $request->get('token');
    // The term array will be returned.
    $term_array = [];

    if (empty($token) || !$this->csrfToken->validate($token, $vid)) {
      return new Response($this->t('Access denied!'));
    }
    $parent = $request->get('parent') ?: 0;
    $depth = $request->get('depth');
    
    if(!empty($depth)) {
      $depth = intval($depth);
    }

    $vocabulary_hierarchy = $this->storageController->getVocabularyHierarchyType($vid);
    // Taxonomy tree must not be multiple parent tree.
    if ($vocabulary_hierarchy !== VocabularyInterface::HIERARCHY_MULTIPLE) {
      $tree = $this->storageController->loadTree($vid, $parent, $depth, TRUE);

      $access_control_handler = $this->entityTypeManager->getAccessControlHandler('taxonomy_term');

      foreach ($tree as $term) {
        if ($term instanceof Term) {
          // User can only access the terms that they can update.
          if ($access_control_handler->access($term, 'update')) {

            $term_array[] = [
              'id' => $term->id(),
              'text' => $term->label(),
              'parent' => $term->parents[0],
              'edit_url' => $term->toUrl('edit-form')->toString(),
            ];
          }
        }
      }
    }

    // Taxonomy setup plugin instance.
    $taxonomy_setup_plugin = $this->setupManager->createInstance('hm_setup_taxonomy');
    // Display profile.
    $display_profile = $this->entityTypeManager->getStorage('hm_display_profile')->load($taxonomy_setup_plugin->getDispalyProfileId());
    // Display plugin ID.
    $display_plugin_id = $display_profile->get("plugin");
    // Display plugin instance.
    $display_plugin = $this->displayManager->createInstance($display_plugin_id);

    if (method_exists($display_plugin, 'treeData')) {
      // Convert the tree data to the structure
      // that display plugin accepts.
      $tree_data = $display_plugin->treeData($term_array);
    }
    else {
      $tree_data = $term_array;
    }

    return new JsonResponse($tree_data);
  }

  /**
   * Callback for taxonomy tree json.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   Http request object.
   * @param string $vid
   *   Vocabulary ID.
   */
  public function updateTerms(Request $request, string $vid) {
    // Access token.
    $token = $request->get('token');
    if (empty($token) || !$this->csrfToken->validate($token, $vid)) {
      return new Response($this->t('Access denied!'));
    }

    $target_position = $request->get('target');
    $parent_id = intval($request->get('parent'));
    $updated_terms = $request->get('keys');
    $success = FALSE;

    if (is_array($updated_terms) && !empty($updated_terms)) {
      // Taxonomy access control.
      $access_control_handler = $this->entityTypeManager->getAccessControlHandler('taxonomy_term');

      // Children of the parent term in weight and name alphabetically order.
      $children = $this->storageController->loadTree($vid, $parent_id, 1);
      if (empty($children)) {
        if (Term::load($parent_id)) {
          // The parent term hasn't had any children.
          $weight = 0;
        }
        else {
          // The parent term doesn't exist.
          return new JsonResponse(['result' => 'fail']);
        }
      }
      else {
        // The parent term has children.
        $target_position = intval($target_position);
        $total = count($children);
        // Move all terms after the target position forward.
        if (isset($children[$target_position])) {
          $weight = (int) $children[$target_position]->weight;
          $tids = [];
          $step = $weight + count($updated_terms);
          for ($i = $target_position; $i < $total; $i++) {
            if ($children[$i]->weight < $step++) {
              $tids[] = $children[$i]->tid;
            }
            else {
              // There is planty room, no need to move anymore.
              break;
            }
          }
          $step = $weight + count($updated_terms);
          $term_siblings = Term::loadMultiple($tids);
          foreach ($term_siblings as $term) {
            $term->setWeight($step++);
            $success = $term->save();
          }
        }
        elseif ($target_position === $total) {
          // Insert into the end.
          $weight = intval(array_slice($children, -1)[0]->weight) + 1;
        }
        else {
          return new JsonResponse(['result' => 'The term is not found.']);
        }
      }
      
      // Load all terms needed to update.
      $terms = Term::loadMultiple($updated_terms);
      // Update all terms, the weight will be increased by 1,
      // after inserting.
      foreach ($terms as $term) {
        if ($access_control_handler->access($term, 'update')) {
          $term->set('parent', ['target_id' => $parent_id]);
          $term->setWeight($weight++);
          $success = $term->save();
        }
      }
    }

    if ($success) {
      return new JsonResponse(['result' => 'success']);
    }

    return new JsonResponse(['result' => 'fail']);
  }

}