10173e75dSAndreas Gohr<?php 20173e75dSAndreas Gohr/** 30173e75dSAndreas Gohr * DokuWiki Plugin struct (Action Component) 40173e75dSAndreas Gohr * 50173e75dSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 60173e75dSAndreas Gohr * @author Andreas Gohr, Michael Große <dokuwiki@cosmocode.de> 70173e75dSAndreas Gohr */ 80173e75dSAndreas Gohr 90173e75dSAndreas Gohr// must be run within Dokuwiki 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 170173e75dSAndreas Gohrif(!defined('DOKU_INC')) die(); 180173e75dSAndreas Gohr 190173e75dSAndreas Gohrclass action_plugin_struct_move extends DokuWiki_Action_Plugin { 200173e75dSAndreas Gohr 215a1a3bb1SAndreas Gohr /** @var helper_plugin_sqlite */ 225a1a3bb1SAndreas Gohr protected $db = null; 235a1a3bb1SAndreas Gohr 240173e75dSAndreas Gohr /** 250173e75dSAndreas Gohr * Registers a callback function for a given event 260173e75dSAndreas Gohr * 270173e75dSAndreas Gohr * @param Doku_Event_Handler $controller DokuWiki's event controller object 280173e75dSAndreas Gohr * @return void 290173e75dSAndreas Gohr */ 300173e75dSAndreas Gohr public function register(Doku_Event_Handler $controller) { 31aa4884afSAndreas Gohr $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handle_move', true); 32aa4884afSAndreas Gohr $controller->register_hook('PLUGIN_MOVE_MEDIA_RENAME', 'AFTER', $this, 'handle_move', false); 330173e75dSAndreas Gohr } 340173e75dSAndreas Gohr 350173e75dSAndreas Gohr /** 360173e75dSAndreas Gohr * Renames all occurances 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 */ 42aa4884afSAndreas Gohr public function handle_move(Doku_Event $event, $ispage) { 430173e75dSAndreas Gohr /** @var helper_plugin_struct_db $hlp */ 440173e75dSAndreas Gohr $hlp = plugin_load('helper', 'struct_db'); 455a1a3bb1SAndreas Gohr $this->db = $hlp->getDB(false); 465a1a3bb1SAndreas Gohr if(!$this->db) return false; 470173e75dSAndreas Gohr $old = $event->data['src_id']; 480173e75dSAndreas Gohr $new = $event->data['dst_id']; 490173e75dSAndreas Gohr 502cbf8951SAndreas Gohr // prepare work 512cbf8951SAndreas Gohr $this->db->query('BEGIN TRANSACTION'); 522cbf8951SAndreas Gohr 535a1a3bb1SAndreas Gohr // general update of our meta tables 54aa4884afSAndreas Gohr if($ispage) { 555a1a3bb1SAndreas Gohr $this->updateDataTablePIDs($old, $new); 565a1a3bb1SAndreas Gohr $this->updateAssignments($old, $new); 575a1a3bb1SAndreas Gohr $this->updateTitles($old, $new); 58aa4884afSAndreas Gohr } 5907e48105SAndreas Gohr 605a1a3bb1SAndreas Gohr // apply updates to all columns in all schemas depending on type 615a1a3bb1SAndreas Gohr $schemas = Schema::getAll(); 625a1a3bb1SAndreas Gohr foreach($schemas as $table) { 635a1a3bb1SAndreas Gohr $schema = new Schema($table); 645a1a3bb1SAndreas Gohr foreach($schema->getColumns() as $col) { 65aa4884afSAndreas Gohr if($ispage) { 665a1a3bb1SAndreas Gohr switch(get_class($col->getType())) { 675a1a3bb1SAndreas Gohr case Page::class: 68aa4884afSAndreas Gohr $this->updateColumnID($schema, $col, $old, $new, true); 695a1a3bb1SAndreas Gohr break; 705a1a3bb1SAndreas Gohr case Lookup::class: 715a1a3bb1SAndreas Gohr $this->updateColumnLookup($schema, $col, $old, $new); 725a1a3bb1SAndreas Gohr break; 730173e75dSAndreas Gohr } 74aa4884afSAndreas Gohr } else { 75aa4884afSAndreas Gohr switch(get_class($col->getType())) { 76aa4884afSAndreas Gohr case Media::class: 77aa4884afSAndreas Gohr $this->updateColumnID($schema, $col, $old, $new); 78aa4884afSAndreas Gohr break; 795a1a3bb1SAndreas Gohr } 805a1a3bb1SAndreas Gohr } 81aa4884afSAndreas Gohr } 82aa4884afSAndreas Gohr } 832cbf8951SAndreas Gohr 842cbf8951SAndreas Gohr // execute everything 852cbf8951SAndreas Gohr $ok = $this->db->query('COMMIT TRANSACTION'); 862cbf8951SAndreas Gohr if(!$ok) { 872cbf8951SAndreas Gohr $this->db->query('ROLLBACK TRANSACTION'); 882cbf8951SAndreas Gohr return false; 892cbf8951SAndreas Gohr } 9007e48105SAndreas Gohr 910173e75dSAndreas Gohr return true; 920173e75dSAndreas Gohr } 9307e48105SAndreas Gohr 9407e48105SAndreas Gohr /** 955a1a3bb1SAndreas Gohr * Update the pid column of ALL data tables 9607e48105SAndreas Gohr * 975a1a3bb1SAndreas Gohr * (we don't trust the assigments are still there) 985a1a3bb1SAndreas Gohr * 995a1a3bb1SAndreas Gohr * @param string $old old page id 1005a1a3bb1SAndreas Gohr * @param string $new new page id 10107e48105SAndreas Gohr */ 1025a1a3bb1SAndreas Gohr protected function updateDataTablePIDs($old, $new) { 1035a1a3bb1SAndreas Gohr foreach(Schema::getAll('page') as $tbl) { 1045a1a3bb1SAndreas Gohr /** @noinspection SqlResolve */ 1055a1a3bb1SAndreas Gohr $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?"; 1065a1a3bb1SAndreas Gohr $this->db->query($sql, array($new, $old)); 10707e48105SAndreas Gohr 1085a1a3bb1SAndreas Gohr /** @noinspection SqlResolve */ 1095a1a3bb1SAndreas Gohr $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?"; 1105a1a3bb1SAndreas Gohr $this->db->query($sql, array($new, $old)); 1115a1a3bb1SAndreas Gohr } 1125a1a3bb1SAndreas Gohr } 11307e48105SAndreas Gohr 1145a1a3bb1SAndreas Gohr /** 1155a1a3bb1SAndreas Gohr * Update the page-schema assignments 1165a1a3bb1SAndreas Gohr * 1175a1a3bb1SAndreas Gohr * @param string $old old page id 1185a1a3bb1SAndreas Gohr * @param string $new new page id 1195a1a3bb1SAndreas Gohr */ 1205a1a3bb1SAndreas Gohr protected function updateAssignments($old, $new) { 1215a1a3bb1SAndreas Gohr // assignments 1225a1a3bb1SAndreas Gohr $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?"; 1235a1a3bb1SAndreas Gohr $this->db->query($sql, array($new, $old)); 1245a1a3bb1SAndreas Gohr // make sure assignments still match patterns; 1255a1a3bb1SAndreas Gohr $assignments = Assignments::getInstance(); 1265a1a3bb1SAndreas Gohr $assignments->reevaluatePageAssignments($new); 1275a1a3bb1SAndreas Gohr } 1285a1a3bb1SAndreas Gohr 1295a1a3bb1SAndreas Gohr /** 1305a1a3bb1SAndreas Gohr * Update the Title information for the moved page 1315a1a3bb1SAndreas Gohr * 1325a1a3bb1SAndreas Gohr * @param string $old old page id 1335a1a3bb1SAndreas Gohr * @param string $new new page id 1345a1a3bb1SAndreas Gohr */ 1355a1a3bb1SAndreas Gohr protected function updateTitles($old, $new) { 1365a1a3bb1SAndreas Gohr $sql = "UPDATE titles SET pid = ? WHERE pid = ?"; 1375a1a3bb1SAndreas Gohr $this->db->query($sql, array($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 */ 149aa4884afSAndreas Gohr protected function updateColumnID(Schema $schema, Column $col, $old, $new, $hashes = false) { 15007e48105SAndreas Gohr $colref = $col->getColref(); 1515a1a3bb1SAndreas Gohr $table = $schema->getTable(); 1525a1a3bb1SAndreas Gohr 15307e48105SAndreas Gohr if($col->isMulti()) { 15407e48105SAndreas Gohr /** @noinspection SqlResolve */ 15507e48105SAndreas Gohr $sql = "UPDATE multi_$table 15607e48105SAndreas Gohr SET value = REPLACE(value, ?, ?) 15707e48105SAndreas Gohr WHERE value LIKE ? 15807e48105SAndreas Gohr AND colref = $colref 15907e48105SAndreas Gohr AND latest = 1"; 16007e48105SAndreas Gohr 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 } 1685a1a3bb1SAndreas Gohr $this->db->query($sql, $old, $new, $old); // exact match 169aa4884afSAndreas Gohr if($hashes) { 1705a1a3bb1SAndreas Gohr $this->db->query($sql, $old, $new, "$old#%"); // match with hashes 17107e48105SAndreas Gohr } 172aa4884afSAndreas Gohr } 1735a1a3bb1SAndreas Gohr 1745a1a3bb1SAndreas Gohr /** 1755a1a3bb1SAndreas Gohr * Update a Lookup type column 1765a1a3bb1SAndreas Gohr * 1775a1a3bb1SAndreas Gohr * Lookups contain a page id when the referenced schema is a data schema 1785a1a3bb1SAndreas Gohr * 1795a1a3bb1SAndreas Gohr * @param Schema $schema 1805a1a3bb1SAndreas Gohr * @param Column $col 1815a1a3bb1SAndreas Gohr * @param string $old old page id 1825a1a3bb1SAndreas Gohr * @param string $new new page id 1835a1a3bb1SAndreas Gohr */ 1845a1a3bb1SAndreas Gohr protected function updateColumnLookup(Schema $schema, Column $col, $old, $new) { 1855a1a3bb1SAndreas Gohr $tconf = $col->getType()->getConfig(); 1865a1a3bb1SAndreas Gohr $ref = new Schema($tconf['schema']); 1875a1a3bb1SAndreas Gohr if(!$ref->getId()) return; // this schema does not exist 188*0ceefd5cSAnna Dabrowska // FIXME does this make sense at all? it's always a lookup, isn't it? 189*0ceefd5cSAnna Dabrowska if(!$ref->getTimeStamp()) return; // a lookup is referenced, nothing to do 190*0ceefd5cSAnna Dabrowska// var_dump($ref) && die(); 1915a1a3bb1SAndreas Gohr 192*0ceefd5cSAnna Dabrowska// $this->updateColumnID($schema, $col, $old, $new); 19307e48105SAndreas Gohr } 194aa4884afSAndreas Gohr 1950173e75dSAndreas Gohr} 196