10173e75dSAndreas Gohr<?php 2d6d97f60SAnna Dabrowska 30173e75dSAndreas Gohr/** 40173e75dSAndreas Gohr * DokuWiki Plugin struct (Action Component) 50173e75dSAndreas Gohr * 60173e75dSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 70173e75dSAndreas Gohr * @author Andreas Gohr, Michael Große <dokuwiki@cosmocode.de> 80173e75dSAndreas Gohr */ 90173e75dSAndreas Gohr 10ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Assignments; 115a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\meta\Column; 12ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Schema; 135a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Lookup; 14aa4884afSAndreas Gohruse dokuwiki\plugin\struct\types\Media; 155a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Page; 160173e75dSAndreas Gohr 17d6d97f60SAnna Dabrowskaclass action_plugin_struct_move extends DokuWiki_Action_Plugin 18d6d97f60SAnna Dabrowska{ 190173e75dSAndreas Gohr 205a1a3bb1SAndreas Gohr /** @var helper_plugin_sqlite */ 215a1a3bb1SAndreas Gohr protected $db = null; 225a1a3bb1SAndreas Gohr 230173e75dSAndreas Gohr /** 240173e75dSAndreas Gohr * Registers a callback function for a given event 250173e75dSAndreas Gohr * 260173e75dSAndreas Gohr * @param Doku_Event_Handler $controller DokuWiki's event controller object 270173e75dSAndreas Gohr * @return void 280173e75dSAndreas Gohr */ 29d6d97f60SAnna Dabrowska public function register(Doku_Event_Handler $controller) 30d6d97f60SAnna Dabrowska { 31748e747fSAnna Dabrowska $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handleMove', true); 32748e747fSAnna Dabrowska $controller->register_hook('PLUGIN_MOVE_MEDIA_RENAME', 'AFTER', $this, 'handleMove', false); 330173e75dSAndreas Gohr } 340173e75dSAndreas Gohr 350173e75dSAndreas Gohr /** 36*5b808f9fSAnna Dabrowska * Renames all occurrences of a page ID in the database 370173e75dSAndreas Gohr * 380173e75dSAndreas Gohr * @param Doku_Event $event event object by reference 39aa4884afSAndreas Gohr * @param bool $ispage is this a page move operation? 400173e75dSAndreas Gohr * @return bool 410173e75dSAndreas Gohr */ 42748e747fSAnna Dabrowska public function handleMove(Doku_Event $event, $ispage) 43d6d97f60SAnna Dabrowska { 440173e75dSAndreas Gohr /** @var helper_plugin_struct_db $hlp */ 450173e75dSAndreas Gohr $hlp = plugin_load('helper', 'struct_db'); 465a1a3bb1SAndreas Gohr $this->db = $hlp->getDB(false); 475a1a3bb1SAndreas Gohr if (!$this->db) return false; 480173e75dSAndreas Gohr $old = $event->data['src_id']; 490173e75dSAndreas Gohr $new = $event->data['dst_id']; 500173e75dSAndreas Gohr 512cbf8951SAndreas Gohr // prepare work 522cbf8951SAndreas Gohr $this->db->query('BEGIN TRANSACTION'); 532cbf8951SAndreas Gohr 545a1a3bb1SAndreas Gohr // general update of our meta tables 55aa4884afSAndreas Gohr if ($ispage) { 565a1a3bb1SAndreas Gohr $this->updateDataTablePIDs($old, $new); 575a1a3bb1SAndreas Gohr $this->updateAssignments($old, $new); 585a1a3bb1SAndreas Gohr $this->updateTitles($old, $new); 59aa4884afSAndreas Gohr } 6007e48105SAndreas Gohr 615a1a3bb1SAndreas Gohr // apply updates to all columns in all schemas depending on type 625a1a3bb1SAndreas Gohr $schemas = Schema::getAll(); 635a1a3bb1SAndreas Gohr foreach ($schemas as $table) { 645a1a3bb1SAndreas Gohr $schema = new Schema($table); 655a1a3bb1SAndreas Gohr foreach ($schema->getColumns() as $col) { 66aa4884afSAndreas Gohr if ($ispage) { 675a1a3bb1SAndreas Gohr switch (get_class($col->getType())) { 685a1a3bb1SAndreas Gohr case Page::class: 69aa4884afSAndreas Gohr $this->updateColumnID($schema, $col, $old, $new, true); 705a1a3bb1SAndreas Gohr break; 715a1a3bb1SAndreas Gohr case Lookup::class: 725a1a3bb1SAndreas Gohr $this->updateColumnLookup($schema, $col, $old, $new); 735a1a3bb1SAndreas Gohr break; 740173e75dSAndreas Gohr } 75aa4884afSAndreas Gohr } else { 76aa4884afSAndreas Gohr switch (get_class($col->getType())) { 77aa4884afSAndreas Gohr case Media::class: 78aa4884afSAndreas Gohr $this->updateColumnID($schema, $col, $old, $new); 79aa4884afSAndreas Gohr break; 805a1a3bb1SAndreas Gohr } 815a1a3bb1SAndreas Gohr } 82aa4884afSAndreas Gohr } 83aa4884afSAndreas Gohr } 842cbf8951SAndreas Gohr 852cbf8951SAndreas Gohr // execute everything 862cbf8951SAndreas Gohr $ok = $this->db->query('COMMIT TRANSACTION'); 872cbf8951SAndreas Gohr if (!$ok) { 882cbf8951SAndreas Gohr $this->db->query('ROLLBACK TRANSACTION'); 892cbf8951SAndreas Gohr return false; 902cbf8951SAndreas Gohr } 9107e48105SAndreas Gohr 920173e75dSAndreas Gohr return true; 930173e75dSAndreas Gohr } 9407e48105SAndreas Gohr 9507e48105SAndreas Gohr /** 965a1a3bb1SAndreas Gohr * Update the pid column of ALL data tables 9707e48105SAndreas Gohr * 985a1a3bb1SAndreas Gohr * (we don't trust the assigments are still there) 995a1a3bb1SAndreas Gohr * 1005a1a3bb1SAndreas Gohr * @param string $old old page id 1015a1a3bb1SAndreas Gohr * @param string $new new page id 10207e48105SAndreas Gohr */ 103d6d97f60SAnna Dabrowska protected function updateDataTablePIDs($old, $new) 104d6d97f60SAnna Dabrowska { 105*5b808f9fSAnna Dabrowska foreach (Schema::getAll() as $tbl) { 1065a1a3bb1SAndreas Gohr /** @noinspection SqlResolve */ 1075a1a3bb1SAndreas Gohr $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?"; 1085a1a3bb1SAndreas Gohr $this->db->query($sql, array($new, $old)); 10907e48105SAndreas Gohr 1105a1a3bb1SAndreas Gohr /** @noinspection SqlResolve */ 1115a1a3bb1SAndreas Gohr $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?"; 1125a1a3bb1SAndreas Gohr $this->db->query($sql, array($new, $old)); 1135a1a3bb1SAndreas Gohr } 1145a1a3bb1SAndreas Gohr } 11507e48105SAndreas Gohr 1165a1a3bb1SAndreas Gohr /** 1175a1a3bb1SAndreas Gohr * Update the page-schema assignments 1185a1a3bb1SAndreas Gohr * 1195a1a3bb1SAndreas Gohr * @param string $old old page id 1205a1a3bb1SAndreas Gohr * @param string $new new page id 1215a1a3bb1SAndreas Gohr */ 122d6d97f60SAnna Dabrowska protected function updateAssignments($old, $new) 123d6d97f60SAnna Dabrowska { 1245a1a3bb1SAndreas Gohr // assignments 1255a1a3bb1SAndreas Gohr $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?"; 1265a1a3bb1SAndreas Gohr $this->db->query($sql, array($new, $old)); 1275a1a3bb1SAndreas Gohr // make sure assignments still match patterns; 1285a1a3bb1SAndreas Gohr $assignments = Assignments::getInstance(); 1295a1a3bb1SAndreas Gohr $assignments->reevaluatePageAssignments($new); 1305a1a3bb1SAndreas Gohr } 1315a1a3bb1SAndreas Gohr 1325a1a3bb1SAndreas Gohr /** 1335a1a3bb1SAndreas Gohr * Update the Title information for the moved page 1345a1a3bb1SAndreas Gohr * 1355a1a3bb1SAndreas Gohr * @param string $old old page id 1365a1a3bb1SAndreas Gohr * @param string $new new page id 1375a1a3bb1SAndreas Gohr */ 138d6d97f60SAnna Dabrowska protected function updateTitles($old, $new) 139d6d97f60SAnna Dabrowska { 1405a1a3bb1SAndreas Gohr $sql = "UPDATE titles SET pid = ? WHERE pid = ?"; 1415a1a3bb1SAndreas Gohr $this->db->query($sql, array($new, $old)); 1425a1a3bb1SAndreas Gohr } 1435a1a3bb1SAndreas Gohr 1445a1a3bb1SAndreas Gohr /** 145aa4884afSAndreas Gohr * Update the ID in a given column 1465a1a3bb1SAndreas Gohr * 1475a1a3bb1SAndreas Gohr * @param Schema $schema 1485a1a3bb1SAndreas Gohr * @param Column $col 1495a1a3bb1SAndreas Gohr * @param string $old old page id 1505a1a3bb1SAndreas Gohr * @param string $new new page id 151aa4884afSAndreas Gohr * @param bool $hashes could the ID have a hash part? (for Page type) 1525a1a3bb1SAndreas Gohr */ 153d6d97f60SAnna Dabrowska protected function updateColumnID(Schema $schema, Column $col, $old, $new, $hashes = false) 154d6d97f60SAnna Dabrowska { 15507e48105SAndreas Gohr $colref = $col->getColref(); 1565a1a3bb1SAndreas Gohr $table = $schema->getTable(); 1575a1a3bb1SAndreas Gohr 15807e48105SAndreas Gohr if ($col->isMulti()) { 15907e48105SAndreas Gohr /** @noinspection SqlResolve */ 16007e48105SAndreas Gohr $sql = "UPDATE multi_$table 16107e48105SAndreas Gohr SET value = REPLACE(value, ?, ?) 16207e48105SAndreas Gohr WHERE value LIKE ? 16307e48105SAndreas Gohr AND colref = $colref 16407e48105SAndreas Gohr AND latest = 1"; 16507e48105SAndreas Gohr } else { 16607e48105SAndreas Gohr /** @noinspection SqlResolve */ 16707e48105SAndreas Gohr $sql = "UPDATE data_$table 16807e48105SAndreas Gohr SET col$colref = REPLACE(col$colref, ?, ?) 16907e48105SAndreas Gohr WHERE col$colref LIKE ? 17007e48105SAndreas Gohr AND latest = 1"; 17107e48105SAndreas Gohr } 1725a1a3bb1SAndreas Gohr $this->db->query($sql, $old, $new, $old); // exact match 173aa4884afSAndreas Gohr if ($hashes) { 1745a1a3bb1SAndreas Gohr $this->db->query($sql, $old, $new, "$old#%"); // match with hashes 17507e48105SAndreas Gohr } 176dd40f4d1SAnna Dabrowska if (get_class($col->getType()) === Lookup::class) { 177dd40f4d1SAnna Dabrowska $this->db->query($sql, $old, $new, "[\"$old\",%]"); // match JSON string 178dd40f4d1SAnna Dabrowska if ($hashes) { 179dd40f4d1SAnna Dabrowska $this->db->query($sql, $old, $new, "[\"$old#%\",%]"); // match JSON string with hash 180dd40f4d1SAnna Dabrowska } 181dd40f4d1SAnna Dabrowska } 182aa4884afSAndreas Gohr } 1835a1a3bb1SAndreas Gohr 1845a1a3bb1SAndreas Gohr /** 1855a1a3bb1SAndreas Gohr * Update a Lookup type column 1865a1a3bb1SAndreas Gohr * 1875a1a3bb1SAndreas Gohr * Lookups contain a page id when the referenced schema is a data schema 1885a1a3bb1SAndreas Gohr * 1895a1a3bb1SAndreas Gohr * @param Schema $schema 1905a1a3bb1SAndreas Gohr * @param Column $col 1915a1a3bb1SAndreas Gohr * @param string $old old page id 1925a1a3bb1SAndreas Gohr * @param string $new new page id 1935a1a3bb1SAndreas Gohr */ 194d6d97f60SAnna Dabrowska protected function updateColumnLookup(Schema $schema, Column $col, $old, $new) 195d6d97f60SAnna Dabrowska { 1965a1a3bb1SAndreas Gohr $tconf = $col->getType()->getConfig(); 1975a1a3bb1SAndreas Gohr $ref = new Schema($tconf['schema']); 1985a1a3bb1SAndreas Gohr if (!$ref->getId()) return; // this schema does not exist 1990ceefd5cSAnna Dabrowska if (!$ref->getTimeStamp()) return; // a lookup is referenced, nothing to do 20010575566SAnna Dabrowska $this->updateColumnID($schema, $col, $old, $new); 20107e48105SAndreas Gohr } 2020173e75dSAndreas Gohr} 203