From 241783fad82aaaa0167316e58ffb5ec3660a012e Mon Sep 17 00:00:00 2001 From: Thomas Hackl Date: Wed, 9 Jul 2025 08:56:42 +0200 Subject: adjust to new int root ID --- app/controllers/admin/tree.php | 4 +- app/views/admin/tree/edit.php | 2 +- db/migrations/6.1.2_tree_node_path.php | 66 --------------------- db/migrations/6.1.6_tree_node_path.php | 71 +++++++++++++++++++++++ lib/classes/JsonApi/Schemas/TreeNode.php | 2 +- lib/models/StudipStudyArea.php | 46 ++++++++------- resources/vue/components/tree/StudipTreeList.vue | 4 +- resources/vue/components/tree/StudipTreeNode.vue | 8 +-- resources/vue/components/tree/StudipTreeTable.vue | 2 +- 9 files changed, 107 insertions(+), 98 deletions(-) delete mode 100644 db/migrations/6.1.2_tree_node_path.php create mode 100644 db/migrations/6.1.6_tree_node_path.php diff --git a/app/controllers/admin/tree.php b/app/controllers/admin/tree.php index 5d22775..8a307c8 100644 --- a/app/controllers/admin/tree.php +++ b/app/controllers/admin/tree.php @@ -22,7 +22,7 @@ class Admin_TreeController extends AuthenticatedController 'editable' => true, 'semester' => $this->semester, 'show-structure-as-navigation' => true, - 'start-id' => Request::get('node_id', 'RangeTreeNode_root'), + 'start-id' => Request::get('node_id', 'RangeTreeNode_0'), 'title' => _('Einrichtungshierarchie bearbeiten'), 'view-type' => 'table', 'visible-children-only' => false, @@ -52,7 +52,7 @@ class Admin_TreeController extends AuthenticatedController 'editable' => true, 'semester' => $this->semester, 'show-structure-as-navigation' => true, - 'start-id' => Request::get('node_id', 'StudipStudyArea_root'), + 'start-id' => Request::get('node_id', 'StudipStudyArea_' . StudipStudyArea::ROOT), 'title' => _('Veranstaltungshierarchie bearbeiten'), 'view-type' => 'table', 'visible-children-only' => false, diff --git a/app/views/admin/tree/edit.php b/app/views/admin/tree/edit.php index 0076b95..15f6b07 100644 --- a/app/views/admin/tree/edit.php +++ b/app/views/admin/tree/edit.php @@ -24,7 +24,7 @@ diff --git a/db/migrations/6.1.2_tree_node_path.php b/db/migrations/6.1.2_tree_node_path.php deleted file mode 100644 index 76468da..0000000 --- a/db/migrations/6.1.2_tree_node_path.php +++ /dev/null @@ -1,66 +0,0 @@ -exec("ALTER TABLE `sem_tree` - ADD `ancestors` VARCHAR(255) NOT NULL AFTER `parent_id`, - ADD INDEX `ancestors` (`ancestors`)" - ); - StudipStudyArea::expireTableScheme(); - $this->buildStructure(StudipStudyArea::class, 'root', 0, 0, ''); - - DBManager::get()->exec("ALTER TABLE `range_tree` - ADD `ancestors` VARCHAR(255) NOT NULL AFTER `parent_id`, - ADD INDEX `ancestors` (`ancestors`)" - ); - RangeTreeNode::expireTableScheme(); - $this->buildStructure(RangeTreeNode::class, 'root', 0, 0, ''); - - DBManager::get()->exec("ALTER TABLE `sem_tree` - CHANGE `sem_tree_id` `sem_tree_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - CHANGE `parent_id` `parent_id` INT UNSIGNED NOT NULL"); - DBManager::get()->exec("ALTER TABLE `seminar_sem_tree` - CHANGE `sem_tree_id` `sem_tree_id` INT UNSIGNED NOT NULL"); - DBManager::get()->exec("ALTER TABLE `range_tree` - CHANGE `item_id` `item_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - CHANGE `parent_id` `parent_id` INT UNSIGNED NOT NULL"); - } - - public function down() - { - DBManager::get()->exec("ALTER TABLE `sem_tree` DROP `ancestors`"); - DBManager::get()->exec("ALTER TABLE `range_tree` DROP `ancestors`"); - } - - private function buildStructure(string $classname, string $oldParentId, int $newParentId, int $currentId, string $ancestors) - { - foreach ($classname::findByParent_id($oldParentId, "ORDER BY `priority`") as $child) { - $currentId++; - - $oldId = $child->id; - $child->id = $currentId; - $child->parent_id = $newParentId; - $child->ancestors = $ancestors . ($ancestors === '' ? '' : '|') . $newParentId; - $child->store(); - - DBManager::get()->execute( - "UPDATE `seminar_sem_tree` SET `sem_tree_id` = :new WHERE `sem_tree_id` = :old", - ['new' => $child->id, 'old' => $oldId] - ); - - $currentId = $this->buildStructure($classname, $oldId, $child->id, $currentId, $child->ancestors); - } - - return $currentId; - } - -}; - diff --git a/db/migrations/6.1.6_tree_node_path.php b/db/migrations/6.1.6_tree_node_path.php new file mode 100644 index 0000000..35c3bd1 --- /dev/null +++ b/db/migrations/6.1.6_tree_node_path.php @@ -0,0 +1,71 @@ +exec("ALTER TABLE `sem_tree` + ADD `ancestors` VARCHAR(255) NOT NULL AFTER `parent_id`, + ADD INDEX `ancestors` (`ancestors`)" + ); + StudipStudyArea::expireTableScheme(); + $this->buildStructure(StudipStudyArea::class, 'root', 0, 0, ''); + + DBManager::get()->exec("ALTER TABLE `range_tree` + ADD `ancestors` VARCHAR(255) NOT NULL AFTER `parent_id`, + ADD INDEX `ancestors` (`ancestors`)" + ); + RangeTreeNode::expireTableScheme(); + $this->buildStructure(RangeTreeNode::class, 'root', 0, 0, ''); + + DBManager::get()->exec("ALTER TABLE `sem_tree` + CHANGE `sem_tree_id` `sem_tree_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + CHANGE `parent_id` `parent_id` INT UNSIGNED NOT NULL"); + DBManager::get()->exec("ALTER TABLE `seminar_sem_tree` + CHANGE `sem_tree_id` `sem_tree_id` INT UNSIGNED NOT NULL"); + DBManager::get()->exec("ALTER TABLE `range_tree` + CHANGE `item_id` `item_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + CHANGE `parent_id` `parent_id` INT UNSIGNED NOT NULL"); + } + + public function down() + { + DBManager::get()->exec("ALTER TABLE `sem_tree` DROP `ancestors`"); + DBManager::get()->exec("ALTER TABLE `range_tree` DROP `ancestors`"); + } + + private function buildStructure(string $classname, string $oldParentId, int $newParentId, int $currentId, string $ancestors) + { + foreach ($classname::findByParent_id($oldParentId, "ORDER BY `priority`") as $child) { + $currentId++; + $newAncestors = $ancestors; + if ($ancestors !== '') { + $newAncestors .= '|'; + } + $newAncestors .= $newParentId; + + $oldId = $child->id; + $child->id = $currentId; + $child->parent_id = $newParentId; + $child->ancestors = $newAncestors; + $child->store(); + + DBManager::get()->execute( + "UPDATE `seminar_sem_tree` SET `sem_tree_id` = :new WHERE `sem_tree_id` = :old", + ['new' => $child->id, 'old' => $oldId] + ); + + $currentId = $this->buildStructure($classname, $oldId, $child->id, $currentId, $newAncestors); + } + + return $currentId; + } + +}; + diff --git a/lib/classes/JsonApi/Schemas/TreeNode.php b/lib/classes/JsonApi/Schemas/TreeNode.php index 9824450..13c826a 100644 --- a/lib/classes/JsonApi/Schemas/TreeNode.php +++ b/lib/classes/JsonApi/Schemas/TreeNode.php @@ -26,7 +26,7 @@ class TreeNode extends SchemaProvider public function getAttributes($resource, ContextInterface $context): iterable { $schema = [ - 'id' => (string) $resource->getId(), + 'id' => $resource->getId(), 'name' => (string) $resource->getName(), 'description' => (string) $resource->getDescription(), 'description-formatted' => (string) formatReady($resource->getDescription()), diff --git a/lib/models/StudipStudyArea.php b/lib/models/StudipStudyArea.php index c48d5dd..c3121b2 100644 --- a/lib/models/StudipStudyArea.php +++ b/lib/models/StudipStudyArea.php @@ -427,9 +427,9 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode public static function getNode($id): StudipTreeNode { - if ($id === 'root') { + if ($id == static::ROOT) { return static::build([ - 'id' => 'root', + 'id' => self::ROOT, 'name' => Config::get()->UNI_NAME_CLEAN, ]); } @@ -506,7 +506,7 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode $semclass = 0, $with_children = false ): int { - if ($this->id === 'root' && !$with_children) { + if ($this->id == 0 && !$with_children) { return 0; } @@ -519,12 +519,11 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode $query = "SELECT COUNT(DISTINCT t.`seminar_id`) FROM `seminar_sem_tree` t {$condition}"; if ($with_children) { - $query .= " AND t.`sem_tree_id` IN (:ids)"; - $parameters['ids'] = array_merge([$this->id], $this->getDescendantIds()); + $query .= " AND (t.`ancestors` LIKE '%|:id|%' OR t.`ancestors` LIKE ':id|%' OR t.`ancestors` LIKE '%|:id')"; } else { $query .= " AND t.`sem_tree_id` = :id"; - $parameters['id'] = $this->id; } + $parameters['id'] = $this->id; return DBManager::get()->fetchColumn($query, $parameters); } @@ -548,12 +547,11 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode $query = "SELECT DISTINCT s.* FROM `seminar_sem_tree` AS t {$condition}"; if ($with_children) { - $query .= " AND t.`sem_tree_id` IN (:ids)"; - $parameters['ids'] = array_merge([$this->id], $this->getDescendantIds()); + $query .= " AND (t.`ancestors` LIKE '%|:id|%' OR t.`ancestors` LIKE ':id|%' OR t.`ancestors` LIKE '%|:id')"; } else { $query .= " AND t.`sem_tree_id` = :id"; - $parameters['id'] = $this->id; } + $parameters['id'] = $this->id; $query .= " ORDER BY " . implode(', ', $order_by); @@ -562,19 +560,25 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode public function getAncestorNodes(): array { - $path = [ + return array_merge( [ - 'id' => $this->id, - 'name' => $this->getName(), - 'classname' => static::class - ] - ]; - - if ($this->parent_id) { - $path = array_merge($this->getNode($this->parent_id)->getAncestorNodes(), $path); - } - - return $path; + [ + 'id' => static::ROOT, + 'name' => Config::get()->UNI_NAME_CLEAN, + 'classname' => static::class + ] + ], + static::findAndMapMany( + function ($node) { + return [ + 'id' => $node->id, + 'name' => $node->getName(), + 'classname' => static::class + ]; + }, + explode('|', $this->ancestors) + ) + ); } /** diff --git a/resources/vue/components/tree/StudipTreeList.vue b/resources/vue/components/tree/StudipTreeList.vue index e76e29a..53265d9 100644 --- a/resources/vue/components/tree/StudipTreeList.vue +++ b/resources/vue/components/tree/StudipTreeList.vue @@ -1,7 +1,7 @@