Skip to content
Snippets Groups Projects
Commit 10864436 authored by Mingsong Hu's avatar Mingsong Hu
Browse files

Improve hierarchy update algorithm

parent d2c9e782
No related branches found
No related tags found
No related merge requests found
......@@ -168,6 +168,8 @@ class HmMenuController extends ControllerBase {
$updated_links = $request->get('keys');
//$after = $request->get('after');
$before = $request->get('before');
$all_siblings = [];
$insert_after = TRUE;
if (is_array($updated_links) && !empty($updated_links)) {
if (empty($parent)) {
......@@ -186,48 +188,39 @@ class HmMenuController extends ControllerBase {
// The parent menu doesn't exist.
return new JsonResponse(['result' => 'fail']);
}
else {
if (empty($children)) {
$parent_link = reset($parent_links);
$children = $parent_link->subtree;
}
if ($children) {
// The parent menu has children.
$target_position = intval($target_position);
$all_siblings = [];
$insert_after = TRUE;
$position = 0;
foreach ($children as $child) {
$link = $child->link;
$link_id = $link->getPLuginId();
// Figure out if the new links are inserted
// after the target position.
if ($position++ == $target_position && $link_id !== $before) {
$insert_after = FALSE;
}
$all_siblings[$link_id] = (int) $link->getWeight();
if (empty($children)) {
$parent_link = reset($parent_links);
$children = $parent_link->subtree;
}
if ($children) {
// The parent menu has children.
$target_position = intval($target_position);
$position = 0;
foreach ($children as $child) {
$link = $child->link;
$link_id = $link->getPLuginId();
// Figure out if the new links are inserted
// after the target position.
if ($position++ == $target_position && $link_id !== $before) {
$insert_after = FALSE;
}
$new_hierarchy = $this->hmPluginTypeManager->updateHierarchy($target_position, $all_siblings, $updated_links, $insert_after);
$weight = $new_hierarchy['start_weight'];
$moving_siblings = $new_hierarchy['moving_siblings'];
// Update all sibling links needed to update.
foreach ($moving_siblings as $link_id => $link_weight) {
$this->menuLinkManager->updateDefinition($link_id, ['weight' => $link_weight]);
}
}
else {
// The parent link doesn't have children.
$weight = 0;
}
// Move all links updated.
foreach ($updated_links as $link_id) {
$this->menuLinkManager->updateDefinition($link_id, ['weight' => $weight++, 'parent' => $parent]);
$all_siblings[$link_id] = (int) $link->getWeight();
}
}
else {
// The parent link doesn't have children.
}
$new_hierarchy = $this->hmPluginTypeManager->updateHierarchy($target_position, $all_siblings, $updated_links, $insert_after);
// Update all links need to update.
foreach ($new_hierarchy as $link_id => $link_weight) {
$this->menuLinkManager->updateDefinition($link_id, ['weight' => $link_weight, 'parent' => $parent]);
}
return new JsonResponse(['result' => 'success']);
}
......
......@@ -146,6 +146,8 @@ class HmTaxonomyController extends ControllerBase {
//$after = $request->get('after');
$before = $request->get('before');
$success = FALSE;
$insert_after = TRUE;
$all_siblings = [];
if (is_array($updated_terms) && !empty($updated_terms)) {
// Taxonomy access control.
......@@ -156,7 +158,6 @@ class HmTaxonomyController extends ControllerBase {
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.
......@@ -166,8 +167,6 @@ class HmTaxonomyController extends ControllerBase {
else {
// The parent term has children.
$target_position = intval($target_position);
$all_siblings = [];
$insert_after = TRUE;
$position = 0;
foreach ($children as $child) {
......@@ -179,30 +178,18 @@ class HmTaxonomyController extends ControllerBase {
$all_siblings[$child->tid] = (int) $child->weight;
}
$new_hierarchy = $this->hmPluginTypeManager->updateHierarchy($target_position, $all_siblings, $updated_terms, $insert_after);
$weight = $new_hierarchy['start_weight'];
$moving_siblings = $new_hierarchy['moving_siblings'];
$tids = array_keys($moving_siblings);
if (!empty($tids)) {
// Update siblings.
$term_siblings = Term::loadMultiple($tids);
foreach ($term_siblings as $term) {
$term->setWeight($moving_siblings[$term->id()]);
$success = $term->save();
}
}
}
$new_hierarchy = $this->hmPluginTypeManager->updateHierarchy($target_position, $all_siblings, $updated_terms, $insert_after);
$tids = array_keys($new_hierarchy);
// Load all terms needed to update.
$terms = Term::loadMultiple($updated_terms);
// Update all terms, the weight will be increased by 1,
// after inserting.
$terms = Term::loadMultiple($tids);
// Update all terms.
foreach ($terms as $term) {
if ($access_control_handler->access($term, 'update')) {
$term->set('parent', ['target_id' => $parent_id]);
$term->setWeight($weight++);
$term->setWeight($new_hierarchy[$term->id()]);
$success = $term->save();
}
}
......
......@@ -97,107 +97,115 @@ class PluginTypeManager {
* IDs of new items inserted.
* @param int|bool $after
* Indicator if new items are inserted after target position.
* @param int $weight
* The initial weight.
*
* @return array
* All siblings needed to move and their new weights.
*/
public function updateHierarchy(int $target_position, array $all_siblings, array $updated_items, $after) {
$filtered_moving_siblings = [];
public function updateHierarchy(int $target_position, array $all_siblings, array $updated_items, $after, int $weight = 0) {
$new_hierarchy = [];
$first_half = TRUE;
$total = count($all_siblings);
if ($target_position === 0) {
// The insert postion is the first position.
// we don't need to move any siblings.
$weight = (int) reset($all_siblings) - 1;
}
elseif ($target_position >= $total - 1) {
// The insert postion is the end,
// we don't need to move any siblings.
$last_item= array_slice($all_siblings, -1, 1, TRUE);
$weight = (int) reset($last_item) + 1;
}
else {
$target_item = array_slice($all_siblings, $target_position, 1, TRUE);
$weight = (int) reset($target_item);
// If the target position is in the second half,
// we will move all siblings
// after the target position forward.
// Otherwise, we will move siblings
// before the target position backwards.
if ($target_position >= $total / 2) {
$first_half = FALSE;
if ($after) {
// Insert after the target position.
// The target stay where it is.
$weight += 1;
$moving_siblings = array_slice($all_siblings, $target_position + 1, NULL, TRUE);
}
else {
// Insert before the target position.
// The target need to move forwards.
$moving_siblings = array_slice($all_siblings, $target_position, NULL, TRUE);
}
$step = $weight + count($updated_items);
if (!empty($all_siblings)) {
$total = count($all_siblings);
if ($target_position === 0) {
// The insert postion is the first position.
// we don't need to move any siblings.
$weight = (int) reset($all_siblings) - 1;
}
elseif ($target_position >= $total - 1) {
// The insert postion is the end,
// we don't need to move any siblings.
$last_item= array_slice($all_siblings, -1, 1, TRUE);
$weight = (int) reset($last_item) + 1;
}
else {
if ($after) {
// Insert after the target position.
// The target need to move backwards.
$moving_siblings = array_slice($all_siblings, 0, $target_position + 1, TRUE);
$target_item = array_slice($all_siblings, $target_position, 1, TRUE);
$weight = (int) reset($target_item);
// If the target position is in the second half,
// we will move all siblings
// after the target position forward.
// Otherwise, we will move siblings
// before the target position backwards.
if ($target_position >= $total / 2) {
$first_half = FALSE;
if ($after) {
// Insert after the target position.
// The target stay where it is.
$weight += 1;
$moving_siblings = array_slice($all_siblings, $target_position + 1, NULL, TRUE);
}
else {
// Insert before the target position.
// The target need to move forwards.
$moving_siblings = array_slice($all_siblings, $target_position, NULL, TRUE);
}
$step = $weight + count($updated_items);
}
else {
// Insert before the target position.
// The target stay where it is.
$weight -= 1;
$moving_siblings = array_slice($all_siblings, 0, $target_position, TRUE);
}
$weight = $step = $weight - count($updated_items);
// Reverse the siblings_moved array
// as we will decrease the weight
// starting from the first element
// and the new weight should be in
// an opposite order.
$moving_siblings = array_reverse($moving_siblings, TRUE);
}
// Move all siblings that need to move.
foreach($moving_siblings as $item_id => $item_weight) {
// Skip all links in the updated array. They will be moved later.
if (in_array($item_id, $updated_items)) {
continue;
}
if ($first_half) {
// While moving the first half of the siblings,
// all moving siblings' weight are decreased,
// if they are greater than the step.
if ((int)$item_weight < --$step) {
// There is planty room, no need to move anymore.
break;
if ($after) {
// Insert after the target position.
// The target need to move backwards.
$moving_siblings = array_slice($all_siblings, 0, $target_position + 1, TRUE);
}
else {
// Update the weight.
$filtered_moving_siblings[$item_id] = $step;
// Insert before the target position.
// The target stay where it is.
$weight -= 1;
$moving_siblings = array_slice($all_siblings, 0, $target_position, TRUE);
}
$weight = $step = $weight - count($updated_items);
// Reverse the siblings_moved array
// as we will decrease the weight
// starting from the first element
// and the new weight should be in
// an opposite order.
$moving_siblings = array_reverse($moving_siblings, TRUE);
}
else {
// While moving the second half of the siblings,
// all moving siblings' weight are increased,
// if they are less than the step.
if ((int)$item_weight < ++$step) {
// Update the weight.
$filtered_moving_siblings[$item_id] = $step;
// Move all siblings that need to move.
foreach($moving_siblings as $item_id => $item_weight) {
// Skip all links in the updated array. They will be moved later.
if (in_array($item_id, $updated_items)) {
continue;
}
if ($first_half) {
// While moving the first half of the siblings,
// all moving siblings' weight are decreased,
// if they are greater than the step.
if ((int)$item_weight < --$step) {
// There is planty room, no need to move anymore.
break;
}
else {
// Update the weight.
$new_hierarchy[$item_id] = $step;
}
}
else {
// There is planty room, no need to move anymore.
break;
// While moving the second half of the siblings,
// all moving siblings' weight are increased,
// if they are less than the step.
if ((int)$item_weight < ++$step) {
// Update the weight.
$new_hierarchy[$item_id] = $step;
}
else {
// There is planty room, no need to move anymore.
break;
}
}
}
}
}
return ['start_weight' => $weight, 'moving_siblings' => $filtered_moving_siblings];
foreach ($updated_items as $item) {
$new_hierarchy[$item] = $weight++;
}
return $new_hierarchy;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment