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 107234bfb1Ssplitbrainuse dokuwiki\Extension\ActionPlugin; 117234bfb1Ssplitbrainuse dokuwiki\Extension\EventHandler; 127234bfb1Ssplitbrainuse dokuwiki\Extension\Event; 137234bfb1Ssplitbrainuse dokuwiki\plugin\sqlite\SQLiteDB; 14ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Assignments; 155a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\meta\Column; 16ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Schema; 175a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Lookup; 18aa4884afSAndreas Gohruse dokuwiki\plugin\struct\types\Media; 195a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Page; 200173e75dSAndreas Gohr 217234bfb1Ssplitbrainclass action_plugin_struct_move extends ActionPlugin 22d6d97f60SAnna Dabrowska{ 235a1a3bb1SAndreas Gohr /** @var helper_plugin_sqlite */ 247234bfb1Ssplitbrain protected $db; 255a1a3bb1SAndreas Gohr 260173e75dSAndreas Gohr /** 270173e75dSAndreas Gohr * Registers a callback function for a given event 280173e75dSAndreas Gohr * 29*5e29103aSannda * @param EventHandler $controller DokuWiki's event controller object 300173e75dSAndreas Gohr * @return void 310173e75dSAndreas Gohr */ 327234bfb1Ssplitbrain public function register(EventHandler $controller) 33d6d97f60SAnna Dabrowska { 34748e747fSAnna Dabrowska $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handleMove', true); 35748e747fSAnna Dabrowska $controller->register_hook('PLUGIN_MOVE_MEDIA_RENAME', 'AFTER', $this, 'handleMove', false); 360173e75dSAndreas Gohr } 370173e75dSAndreas Gohr 380173e75dSAndreas Gohr /** 395b808f9fSAnna Dabrowska * Renames all occurrences of a page ID in the database 400173e75dSAndreas Gohr * 41*5e29103aSannda * @param Event $event event object by reference 42aa4884afSAndreas Gohr * @param bool $ispage is this a page move operation? 430173e75dSAndreas Gohr * @return bool 440173e75dSAndreas Gohr */ 457234bfb1Ssplitbrain public function handleMove(Event $event, $ispage) 46d6d97f60SAnna Dabrowska { 470173e75dSAndreas Gohr /** @var helper_plugin_struct_db $hlp */ 480173e75dSAndreas Gohr $hlp = plugin_load('helper', 'struct_db'); 495a1a3bb1SAndreas Gohr $this->db = $hlp->getDB(false); 507234bfb1Ssplitbrain if (!$this->db instanceof SQLiteDB) return false; 510173e75dSAndreas Gohr $old = $event->data['src_id']; 520173e75dSAndreas Gohr $new = $event->data['dst_id']; 530173e75dSAndreas Gohr 542cbf8951SAndreas Gohr // prepare work 552cbf8951SAndreas Gohr $this->db->query('BEGIN TRANSACTION'); 562cbf8951SAndreas Gohr 575a1a3bb1SAndreas Gohr // general update of our meta tables 58aa4884afSAndreas Gohr if ($ispage) { 595a1a3bb1SAndreas Gohr $this->updateDataTablePIDs($old, $new); 605a1a3bb1SAndreas Gohr $this->updateAssignments($old, $new); 615a1a3bb1SAndreas Gohr $this->updateTitles($old, $new); 62aa4884afSAndreas Gohr } 6307e48105SAndreas Gohr 645a1a3bb1SAndreas Gohr // apply updates to all columns in all schemas depending on type 655a1a3bb1SAndreas Gohr $schemas = Schema::getAll(); 665a1a3bb1SAndreas Gohr foreach ($schemas as $table) { 675a1a3bb1SAndreas Gohr $schema = new Schema($table); 685a1a3bb1SAndreas Gohr foreach ($schema->getColumns() as $col) { 69aa4884afSAndreas Gohr if ($ispage) { 707234bfb1Ssplitbrain if (get_class($col->getType()) == Page::class) { 71aa4884afSAndreas Gohr $this->updateColumnID($schema, $col, $old, $new, true); 727234bfb1Ssplitbrain } elseif (get_class($col->getType()) == Lookup::class) { 735a1a3bb1SAndreas Gohr $this->updateColumnLookup($schema, $col, $old, $new); 740173e75dSAndreas Gohr } 757234bfb1Ssplitbrain } elseif ($col->getType() instanceof Media) { 76aa4884afSAndreas Gohr $this->updateColumnID($schema, $col, $old, $new); 775a1a3bb1SAndreas Gohr } 78aa4884afSAndreas Gohr } 79aa4884afSAndreas Gohr } 802cbf8951SAndreas Gohr 812cbf8951SAndreas Gohr // execute everything 822cbf8951SAndreas Gohr $ok = $this->db->query('COMMIT TRANSACTION'); 832cbf8951SAndreas Gohr if (!$ok) { 842cbf8951SAndreas Gohr $this->db->query('ROLLBACK TRANSACTION'); 852cbf8951SAndreas Gohr return false; 862cbf8951SAndreas Gohr } 8707e48105SAndreas Gohr 880173e75dSAndreas Gohr return true; 890173e75dSAndreas Gohr } 9007e48105SAndreas Gohr 9107e48105SAndreas Gohr /** 925a1a3bb1SAndreas Gohr * Update the pid column of ALL data tables 9307e48105SAndreas Gohr * 945a1a3bb1SAndreas Gohr * (we don't trust the assigments are still there) 955a1a3bb1SAndreas Gohr * 965a1a3bb1SAndreas Gohr * @param string $old old page id 975a1a3bb1SAndreas Gohr * @param string $new new page id 9807e48105SAndreas Gohr */ 99d6d97f60SAnna Dabrowska protected function updateDataTablePIDs($old, $new) 100d6d97f60SAnna Dabrowska { 1015b808f9fSAnna Dabrowska foreach (Schema::getAll() as $tbl) { 1025a1a3bb1SAndreas Gohr /** @noinspection SqlResolve */ 1035a1a3bb1SAndreas Gohr $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?"; 1047234bfb1Ssplitbrain $this->db->query($sql, [$new, $old]); 10507e48105SAndreas Gohr 1065a1a3bb1SAndreas Gohr /** @noinspection SqlResolve */ 1075a1a3bb1SAndreas Gohr $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?"; 1087234bfb1Ssplitbrain $this->db->query($sql, [$new, $old]); 1095a1a3bb1SAndreas Gohr } 1105a1a3bb1SAndreas Gohr } 11107e48105SAndreas Gohr 1125a1a3bb1SAndreas Gohr /** 1135a1a3bb1SAndreas Gohr * Update the page-schema assignments 1145a1a3bb1SAndreas Gohr * 1155a1a3bb1SAndreas Gohr * @param string $old old page id 1165a1a3bb1SAndreas Gohr * @param string $new new page id 1175a1a3bb1SAndreas Gohr */ 118d6d97f60SAnna Dabrowska protected function updateAssignments($old, $new) 119d6d97f60SAnna Dabrowska { 1205a1a3bb1SAndreas Gohr // assignments 1215a1a3bb1SAndreas Gohr $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?"; 1227234bfb1Ssplitbrain $this->db->query($sql, [$new, $old]); 1235a1a3bb1SAndreas Gohr // make sure assignments still match patterns; 1245a1a3bb1SAndreas Gohr $assignments = Assignments::getInstance(); 1255a1a3bb1SAndreas Gohr $assignments->reevaluatePageAssignments($new); 1265a1a3bb1SAndreas Gohr } 1275a1a3bb1SAndreas Gohr 1285a1a3bb1SAndreas Gohr /** 1295a1a3bb1SAndreas Gohr * Update the Title information for the moved page 1305a1a3bb1SAndreas Gohr * 1315a1a3bb1SAndreas Gohr * @param string $old old page id 1325a1a3bb1SAndreas Gohr * @param string $new new page id 1335a1a3bb1SAndreas Gohr */ 134d6d97f60SAnna Dabrowska protected function updateTitles($old, $new) 135d6d97f60SAnna Dabrowska { 1365a1a3bb1SAndreas Gohr $sql = "UPDATE titles SET pid = ? WHERE pid = ?"; 1377234bfb1Ssplitbrain $this->db->query($sql, [$new, $old]); 1385a1a3bb1SAndreas Gohr } 1395a1a3bb1SAndreas Gohr 1405a1a3bb1SAndreas Gohr /** 141aa4884afSAndreas Gohr * Update the ID in a given column 1425a1a3bb1SAndreas Gohr * 1435a1a3bb1SAndreas Gohr * @param Schema $schema 1445a1a3bb1SAndreas Gohr * @param Column $col 1455a1a3bb1SAndreas Gohr * @param string $old old page id 1465a1a3bb1SAndreas Gohr * @param string $new new page id 147aa4884afSAndreas Gohr * @param bool $hashes could the ID have a hash part? (for Page type) 1485a1a3bb1SAndreas Gohr */ 149d6d97f60SAnna Dabrowska protected function updateColumnID(Schema $schema, Column $col, $old, $new, $hashes = false) 150d6d97f60SAnna Dabrowska { 15107e48105SAndreas Gohr $colref = $col->getColref(); 1525a1a3bb1SAndreas Gohr $table = $schema->getTable(); 1535a1a3bb1SAndreas Gohr 15407e48105SAndreas Gohr if ($col->isMulti()) { 15507e48105SAndreas Gohr /** @noinspection SqlResolve */ 15607e48105SAndreas Gohr $sql = "UPDATE multi_$table 15707e48105SAndreas Gohr SET value = REPLACE(value, ?, ?) 15807e48105SAndreas Gohr WHERE value LIKE ? 15907e48105SAndreas Gohr AND colref = $colref 16007e48105SAndreas Gohr AND latest = 1"; 16107e48105SAndreas Gohr } else { 16207e48105SAndreas Gohr /** @noinspection SqlResolve */ 16307e48105SAndreas Gohr $sql = "UPDATE data_$table 16407e48105SAndreas Gohr SET col$colref = REPLACE(col$colref, ?, ?) 16507e48105SAndreas Gohr WHERE col$colref LIKE ? 16607e48105SAndreas Gohr AND latest = 1"; 16707e48105SAndreas Gohr } 16879b29326SAnna Dabrowska $this->db->query($sql, [$old, $new, $old]); // exact match 169aa4884afSAndreas Gohr if ($hashes) { 17079b29326SAnna Dabrowska $this->db->query($sql, [$old, $new, "$old#%"]); // match with hashes 17107e48105SAndreas Gohr } 1727234bfb1Ssplitbrain if ($col->getType() instanceof Lookup) { 17379b29326SAnna Dabrowska $this->db->query($sql, [$old, $new, "[\"$old\",%]"]); // match JSON string 174dd40f4d1SAnna Dabrowska if ($hashes) { 17579b29326SAnna Dabrowska $this->db->query($sql, [$old, $new, "[\"$old#%\",%]"]); // match JSON string with hash 176dd40f4d1SAnna Dabrowska } 177dd40f4d1SAnna Dabrowska } 178aa4884afSAndreas Gohr } 1795a1a3bb1SAndreas Gohr 1805a1a3bb1SAndreas Gohr /** 1815a1a3bb1SAndreas Gohr * Update a Lookup type column 1825a1a3bb1SAndreas Gohr * 1835a1a3bb1SAndreas Gohr * Lookups contain a page id when the referenced schema is a data schema 1845a1a3bb1SAndreas Gohr * 1855a1a3bb1SAndreas Gohr * @param Schema $schema 1865a1a3bb1SAndreas Gohr * @param Column $col 1875a1a3bb1SAndreas Gohr * @param string $old old page id 1885a1a3bb1SAndreas Gohr * @param string $new new page id 1895a1a3bb1SAndreas Gohr */ 190d6d97f60SAnna Dabrowska protected function updateColumnLookup(Schema $schema, Column $col, $old, $new) 191d6d97f60SAnna Dabrowska { 1925a1a3bb1SAndreas Gohr $tconf = $col->getType()->getConfig(); 1935a1a3bb1SAndreas Gohr $ref = new Schema($tconf['schema']); 1945a1a3bb1SAndreas Gohr if (!$ref->getId()) return; // this schema does not exist 1950ceefd5cSAnna Dabrowska if (!$ref->getTimeStamp()) return; // a lookup is referenced, nothing to do 19610575566SAnna Dabrowska $this->updateColumnID($schema, $col, $old, $new); 19707e48105SAndreas Gohr } 1980173e75dSAndreas Gohr} 199