1<?php 2/** 3 * DokuWiki Plugin struct (Action Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Gohr, Michael Große <dokuwiki@cosmocode.de> 7 */ 8 9// must be run within Dokuwiki 10use dokuwiki\plugin\struct\meta\Assignments; 11use dokuwiki\plugin\struct\meta\Column; 12use dokuwiki\plugin\struct\meta\Schema; 13use dokuwiki\plugin\struct\types\Lookup; 14use dokuwiki\plugin\struct\types\Page; 15 16if(!defined('DOKU_INC')) die(); 17 18class action_plugin_struct_move extends DokuWiki_Action_Plugin { 19 20 /** @var helper_plugin_sqlite */ 21 protected $db = null; 22 23 /** 24 * Registers a callback function for a given event 25 * 26 * @param Doku_Event_Handler $controller DokuWiki's event controller object 27 * @return void 28 */ 29 public function register(Doku_Event_Handler $controller) { 30 $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handle_move'); 31 } 32 33 /** 34 * Renames all occurances of a page ID in the database 35 * 36 * @param Doku_Event $event event object by reference 37 * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 38 * handler was registered] 39 * @return bool 40 */ 41 public function handle_move(Doku_Event $event, $param) { 42 /** @var helper_plugin_struct_db $hlp */ 43 $hlp = plugin_load('helper', 'struct_db'); 44 $this->db = $hlp->getDB(false); 45 if(!$this->db) return false; 46 $old = $event->data['src_id']; 47 $new = $event->data['dst_id']; 48 49 // general update of our meta tables 50 $this->updateDataTablePIDs($old, $new); 51 $this->updateAssignments($old, $new); 52 $this->updateTitles($old, $new); 53 54 // apply updates to all columns in all schemas depending on type 55 $schemas = Schema::getAll(); 56 foreach($schemas as $table) { 57 $schema = new Schema($table); 58 foreach($schema->getColumns() as $col) { 59 switch(get_class($col->getType())) { 60 case Page::class: 61 $this->updateColumnPage($schema, $col, $old, $new); 62 break; 63 case Lookup::class: 64 $this->updateColumnLookup($schema, $col, $old, $new); 65 break; 66 } 67 } 68 } 69 70 // FIXME we need to update Media Type fields on media move 71 // FIXME we should wrap all this in a transaction 72 73 return true; 74 } 75 76 /** 77 * Update the pid column of ALL data tables 78 * 79 * (we don't trust the assigments are still there) 80 * 81 * @param string $old old page id 82 * @param string $new new page id 83 */ 84 protected function updateDataTablePIDs($old, $new) { 85 foreach(Schema::getAll('page') as $tbl) { 86 /** @noinspection SqlResolve */ 87 $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?"; 88 $this->db->query($sql, array($new, $old)); 89 90 /** @noinspection SqlResolve */ 91 $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?"; 92 $this->db->query($sql, array($new, $old)); 93 } 94 } 95 96 /** 97 * Update the page-schema assignments 98 * 99 * @param string $old old page id 100 * @param string $new new page id 101 */ 102 protected function updateAssignments($old, $new) { 103 // assignments 104 $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?"; 105 $this->db->query($sql, array($new, $old)); 106 // make sure assignments still match patterns; 107 $assignments = Assignments::getInstance(); 108 $assignments->reevaluatePageAssignments($new); 109 } 110 111 /** 112 * Update the Title information for the moved page 113 * 114 * @param string $old old page id 115 * @param string $new new page id 116 */ 117 protected function updateTitles($old, $new) { 118 $sql = "UPDATE titles SET pid = ? WHERE pid = ?"; 119 $this->db->query($sql, array($new, $old)); 120 } 121 122 /** 123 * Update a Page type column 124 * 125 * @param Schema $schema 126 * @param Column $col 127 * @param string $old old page id 128 * @param string $new new page id 129 */ 130 protected function updateColumnPage(Schema $schema, Column $col, $old, $new) { 131 $colref = $col->getColref(); 132 $table = $schema->getTable(); 133 134 if($col->isMulti()) { 135 /** @noinspection SqlResolve */ 136 $sql = "UPDATE multi_$table 137 SET value = REPLACE(value, ?, ?) 138 WHERE value LIKE ? 139 AND colref = $colref 140 AND latest = 1"; 141 142 } else { 143 /** @noinspection SqlResolve */ 144 $sql = "UPDATE data_$table 145 SET col$colref = REPLACE(col$colref, ?, ?) 146 WHERE col$colref LIKE ? 147 AND latest = 1"; 148 } 149 $this->db->query($sql, $old, $new, $old); // exact match 150 $this->db->query($sql, $old, $new, "$old#%"); // match with hashes 151 } 152 153 /** 154 * Update a Lookup type column 155 * 156 * Lookups contain a page id when the referenced schema is a data schema 157 * 158 * @param Schema $schema 159 * @param Column $col 160 * @param string $old old page id 161 * @param string $new new page id 162 */ 163 protected function updateColumnLookup(Schema $schema, Column $col, $old, $new) { 164 $tconf = $col->getType()->getConfig(); 165 $ref = new Schema($tconf['schema']); 166 if(!$ref->getId()) return; // this schema does not exist 167 if($ref->isLookup()) return; // a lookup is referenced, nothing to do 168 169 // after the checks it's basically the same as a Page type column 170 $this->updateColumnPage($schema, $col, $old, $new); 171 } 172} 173