Newer
Older

artis.bajars
committed
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityRepositoryInterface;

artis.bajars
committed
use Drupal\Core\Session\AccountInterface;
use Drupal\taxonomy\Entity\Term;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
*/
class HmTaxonomyController extends ControllerBase {
/**
* CSRF Token.
*
* @var \Drupal\Core\Access\CsrfTokenGenerator
*/
protected $csrfToken;
/**
* The term storage handler.
*
* @var \Drupal\taxonomy\TermStorageInterface
*/
protected $storageController;
* The hierarchy manager plugin type manager.
* @var \Drupal\hierarchy_manager\PluginTypeManager
/**
* The entity repository.
*
* @var \Drupal\Core\Entity\EntityRepositoryInterface
*/
protected $entityRepository;
public function __construct(CsrfTokenGenerator $csrfToken, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository, $plugin_type_manager) {
$this->csrfToken = $csrfToken;
$this->entityTypeManager = $entity_type_manager;
$this->entityRepository = $entity_repository;
$this->storageController = $entity_type_manager->getStorage('taxonomy_term');
$this->hmPluginTypeManager = $plugin_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('csrf_token'),
$container->get('entity_type.manager'),
$container->get('hm.plugin_type_manager')

artis.bajars
committed
/**
* Access check callback for taxonomy tree json.
*
* @param \Drupal\Core\Session\AccountInterface $account

artis.bajars
committed
* @param string $vid

artis.bajars
committed
*/
public function access(AccountInterface $account, string $vid) {
if ($account->hasPermission('administer taxonomy')) {
return AccessResult::allowed();
}
return AccessResult::allowedIfHasPermission($account, "edit terms in {$vid}");
}
/**
* 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 = [];
// Store the number of each term id present.
$ids = [];
$am_terms = [];
// Store all terms only have single ancestor.
$single_parent = [];
if (empty($token) || !$this->csrfToken->validate($token, $vid)) {
return new Response($this->t('Access denied!'));
}
$parent = $request->get('parent') ?: 0;
$destination = $request->get('destination');
$tree = $this->storageController->loadTree($vid, $parent, $depth, TRUE);
$access_control_handler = $this->entityTypeManager->getAccessControlHandler('taxonomy_term');
foreach ($tree as $term) {
if ($term instanceof Term) {
$term = $this->entityRepository->getTranslationFromContext($term);
// User can only access the terms that they can update.
if ($access_control_handler->access($term, 'update')) {
if (empty($destination)) {
$url = $term->toUrl('edit-form')->toString();
}
else {
$url = $term->toUrl('edit-form', ['query' => ['destination' => $destination]])->toString();
}
$term_parent = $term->parents;
$id = $term->id();
$count_parent = count($term_parent);
if (isset($ids[$id])) {
if ($ids[$id] === 0 && isset($single_parent[$id])) {
// Update previous term in the term array
// which has the same ID. Make it not draggable.
$term_array[$single_parent[$id]]['draggable'] = FALSE;
}
else {
$ids[$id] = 0;
$term_id = $id;
}
// If a taxonomy term has multiple parents,
// It will present multiple times under different parents.
// So the term id will be duplicated.
// The solution is to format the term id as following,
// {term_id}_{parent_index}.
if ($count_parent > 1) {
$draggable = FALSE;
// This term has an ancestor with multiple parents.
if ($ids[$id] === $count_parent) {
// Put into the ambiguous array.
// Will solve it later.
$am_terms[] = [
'id' => $term_id,
'label' => $term->label(),
'parent' => $term_parent,
'url' => $url,
'publish' => $term->isPublished(),
'weight' => $term->getWeight(),
];
continue;
}
$parent_id = $term_parent[$ids[$id]];
else {
if ($ids[$id]) {
// The parent has multiple grandparent.
$parent_id = $term_parent[0] . '_' . $ids[$id];
}
else {
// The parent doesn't have multiple grandparent.
$parent_id = $term_parent[0];
// At this point, we still don't know
// if this term has multiple ancestors or not.
// So keep the index of term array for later update
// if needed.
$single_parent[$id] = count($term_array);
}
}
$term_array[] = $this->hmPluginTypeManager->buildHierarchyItem(
$term_id,
$term->label(),
$url,
$term->getWeight(),
$draggable
);
// Figure out the parent id for terms in the ambiguous term array.
do {
foreach ($am_terms as $key => $term) {
if ($term['solved']) {
continue;
}
$parent_ids = $term['parent'];
foreach ($parent_ids as $id) {
if ($ids[$id]) {
// Found the parent with multiple grandparent.
$term_array[] = $this->hmPluginTypeManager->buildHierarchyItem(
$term['id'],
$term['label'],
$id . '_' . $ids[$id],
$term['url'],
$term['publish'],
$term['weight'],
$term['draggable']
);
// Remove this parent from ids array.
$ids[$id]--;
// Display profile.
$display_profile = $this->hmPluginTypeManager->getDisplayProfile('hm_setup_taxonomy');
$display_plugin = $this->hmPluginTypeManager->getDisplayPluginInstance($display_profile);
if (empty($display_plugin)) {
return new JsonResponse(['result' => 'Display profile has not been set up.']);
}
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
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!'));
}
$old_position = (int) $request->get('old_position');
$old_parent_id = $request->get('old_parent');
// Remove the parent index from the parent id.
$old_parent_id = explode('_', $old_parent_id)[0];
$parent_id = $request->get('parent');
// Remove the parent index from the parent id.
$parent_id = explode('_', $parent_id)[0];
$updated_terms = $request->get('keys');
$success = FALSE;
if (is_array($updated_terms) && !empty($updated_terms)) {
// Remove the parent index from the term id.
for ($i = 0; $i < count($updated_terms); $i++) {
$updated_terms[$i] = explode('_', $updated_terms[$i])[0];
}
// 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);
foreach ($children as $child) {
$all_siblings[$child->tid] = (int) $child->weight;
}
$new_hierarchy = $this->hmPluginTypeManager->updateHierarchy($target_position, $all_siblings, $updated_terms, $old_position);
$terms = Term::loadMultiple($tids);
// Update all terms.
foreach ($terms as $term) {
if ($access_control_handler->access($term, 'update')) {
$term->setWeight($new_hierarchy[$term->id()]);
// Update the parent IDs.
if (in_array($term->id(), $updated_terms)) {
$parents = [];
$same_parent = $old_parent_id === $parent_id;
// Update the parent only if it is changed.
if (!$same_parent) {
foreach ($term->get('parent') as $parent) {
$tid = $parent->get('target_id')->getValue();
if ($tid === $old_parent_id) {
$tid = $parent_id;
}
elseif ($tid === $parent_id) {
continue;
}
$parents[] = ['target_id' => $tid];
}
// Set the new parent.
$term->set('parent', $parents);
}
}

Mingsong Hu
committed
$result = [
'result' => $success ? 'success' : 'fail',
'updated_nodes' => $new_hierarchy,
];

Mingsong Hu
committed
return new JsonResponse($result);