1<?php 2 3require_once(__DIR__ . '/../ComboStrap/PluginUtility.php'); 4 5use ComboStrap\Alias; 6use ComboStrap\Aliases; 7use ComboStrap\DatabasePageRow; 8use ComboStrap\ExceptionComboRuntime; 9use ComboStrap\File; 10use ComboStrap\LinkUtility; 11use ComboStrap\LogUtility; 12use ComboStrap\MetadataDbStore; 13use ComboStrap\MetadataDokuWikiStore; 14use ComboStrap\Page; 15use ComboStrap\PageId; 16use ComboStrap\PluginUtility; 17use ComboStrap\Site; 18 19 20/** 21 * Class action_plugin_combo_move 22 * Handle the move of a page in order to update: 23 * * the link 24 * * the data in the database 25 */ 26class action_plugin_combo_linkmove extends DokuWiki_Action_Plugin 27{ 28 29 30 const CANONICAL = "move"; 31 32 private static function checkAndSendAMessageIfLockFilePresent(): bool 33 { 34 $lockFile = File::createFromPath(Site::getDataDirectory() . "/locks_plugin_move.lock"); 35 if (!$lockFile->exists()) { 36 return false; 37 } 38 $lockFileDateTimeModified = $lockFile->getModifiedTime(); 39 $lockFileModifiedTimestamp = $lockFileDateTimeModified->getTimestamp(); 40 $now = time(); 41 42 $distance = $now - $lockFileModifiedTimestamp; 43 $lockFileAgeInMinute = ($distance) / 60; 44 if ($lockFileAgeInMinute > 5) { 45 LogUtility::msg("The move lockfile ($lockFile) exists and is older than 5 minutes (exactly $lockFileAgeInMinute minutes). If you are no more in a move, you should delete this file otherwise it will disable the move of page and the cache."); 46 return true; 47 } 48 return false; 49 } 50 51 /** 52 * As explained https://www.dokuwiki.org/plugin:move#support_for_other_plugins 53 * @param Doku_Event_Handler $controller 54 */ 55 function register(Doku_Event_Handler $controller) 56 { 57 58 /** 59 * To rewrite the page meta in the database 60 */ 61 $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'BEFORE', $this, 'handle_rename_before', array()); 62 $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handle_rename_after', array()); 63 64 /** 65 * To rewrite the link 66 */ 67 $controller->register_hook('PLUGIN_MOVE_HANDLERS_REGISTER', 'BEFORE', $this, 'handle_link', array()); 68 69 70 /** 71 * Check for the presence of a lock file 72 */ 73 $controller->register_hook('PARSER_WIKITEXT_PREPROCESS', 'BEFORE', $this, 'check_lock_file_age', array()); 74 75 76 } 77 78 /** 79 * @param Doku_Event $event 80 * @param $params 81 * 82 * When a lock file is present, 83 * the move plugin will purge the data in {@link action_plugin_move_rewrite::handle_cache()} 84 * making the rendering fucking slow 85 * We check that the lock file is not 86 */ 87 function check_lock_file_age(Doku_Event $event, $params) 88 { 89 self::checkAndSendAMessageIfLockFilePresent(); 90 91 } 92 93 /** 94 * Handle the path modification of a page 95 * @param Doku_Event $event - https://www.dokuwiki.org/plugin:move#for_plugin_authors 96 * @param $params 97 * 98 */ 99 function handle_rename_before(Doku_Event $event, $params) 100 { 101 /** 102 * Check that the lock file is not older 103 * Lock file bigger than 5 minutes 104 * Is not really possible 105 */ 106 $result = self::checkAndSendAMessageIfLockFilePresent(); 107 if ($result === true) { 108 $event->preventDefault(); 109 LogUtility::msg("The move lock file is present, the move was canceled."); 110 } 111 112 } 113 114 /** 115 * Handle the path modification of a page after 116 * 117 * The metadata file should also have been moved 118 * 119 * @param Doku_Event $event - https://www.dokuwiki.org/plugin:move#for_plugin_authors 120 * @param $params 121 * 122 */ 123 function handle_rename_after(Doku_Event $event, $params) 124 { 125 /** 126 * 127 * $event->data 128 * src_id ⇒ string – the original ID of the page 129 * dst_id ⇒ string – the new ID of the page 130 */ 131 $sourceId = $event->data["src_id"]; 132 $targetId = $event->data["dst_id"]; 133 try { 134 135 /** 136 * Update the dokuwiki id and path 137 */ 138 $databasePage = DatabasePageRow::createFromDokuWikiId($sourceId); 139 if (!$databasePage->exists()) { 140 return; 141 } 142 $databasePage->updatePathAndDokuwikiId($targetId); 143 144 /** 145 * Check page id 146 */ 147 $targetPage = Page::createPageFromId($targetId); 148 $targetPageId = PageId::createForPage($targetPage); 149 $targetPageIdValue = $targetPageId->getValueFromStore(); 150 $databasePageIdValue = $databasePage->getPageId(); 151 152 if ($databasePageIdValue !== $targetPageIdValue) { 153 // this should never happened in test/dev 154 $targetPageId->setValueForce($targetPageIdValue); 155 } 156 157 /** 158 * Add the alias 159 */ 160 Aliases::createForPage($targetPage) 161 ->addAlias($sourceId) 162 ->setWriteStore(MetadataDokuWikiStore::class) 163 ->sendToWriteStore() 164 ->persist() 165 ->setReadStore(MetadataDbStore::class) 166 ->sendToWriteStore() 167 ->persist(); 168 169 170 } catch (Exception $exception) { 171 // We catch the errors if any to not stop the move 172 // There is no transaction feature (it happens or not) 173 $message = "An error occurred during the move replication to the database. Error message was: " . $exception->getMessage(); 174 if (PluginUtility::isDevOrTest()) { 175 throw new RuntimeException($exception); 176 } else { 177 LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::CANONICAL); 178 } 179 } 180 181 } 182 183 184 /** 185 * Handle the move of a page 186 * @param Doku_Event $event 187 * @param $params 188 */ 189 function handle_link(Doku_Event $event, $params) 190 { 191 /** 192 * The handlers is the name of the component (ie refers to the {@link syntax_plugin_combo_link} handler) 193 * and 'rewrite_combo' to the below method 194 */ 195 $event->data['handlers'][syntax_plugin_combo_link::COMPONENT] = array($this, 'rewrite_combo'); 196 } 197 198 /** 199 * 200 * @param $match 201 * @param $state 202 * @param $pos 203 * @param $plugin 204 * @param helper_plugin_move_handler $handler 205 */ 206 public function rewrite_combo($match, $state, $pos, $plugin, helper_plugin_move_handler $handler) 207 { 208 /** 209 * The original move method 210 * is {@link helper_plugin_move_handler::internallink()} 211 * 212 */ 213 if ($state == DOKU_LEXER_ENTER) { 214 $ref = LinkUtility::parse($match)[LinkUtility::ATTRIBUTE_REF]; 215 $link = new LinkUtility($ref); 216 if ($link->getType() == LinkUtility::TYPE_INTERNAL) { 217 218 $handler->internallink($match, $state, $pos); 219 $suffix = "]]"; 220 if (substr($handler->calls, -strlen($suffix)) == $suffix) { 221 $handler->calls = substr($handler->calls, 0, strlen($handler->calls) - strlen($suffix)); 222 } 223 224 } else { 225 226 // Other type of links 227 $handler->calls .= $match; 228 229 } 230 } else { 231 232 // Description and ending 233 $handler->calls .= $match; 234 235 } 236 } 237 238 239} 240