1<?php 2 3use dokuwiki\plugin\sqlite\Tools; 4 5class action_plugin_structpublish_migration extends DokuWiki_Action_Plugin 6{ 7 const MIN_DB_STRUCT = 19; 8 9 /** @var string */ 10 protected $table = 'data_structpublish'; 11 12 /** 13 * @inheritDoc 14 */ 15 public function register(Doku_Event_Handler $controller) 16 { 17 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleMigrations'); 18 } 19 20 /** 21 * Call our custom migrations. We do not use our own database, 22 * so we cannot use the mechanism in sqlite init() 23 * which processes updateXXXX.sql files 24 * 25 * @param Doku_Event $event 26 * @return bool 27 * @throws Exception 28 */ 29 public function handleMigrations(Doku_Event $event) 30 { 31 /** @var \helper_plugin_struct_db $helper */ 32 $helper = plugin_load('helper', 'struct_db'); 33 34 // abort if struct is not installed 35 if (!$helper) { 36 throw new Exception('Plugin struct is required!'); 37 } 38 39 $sqlite = $helper->getDB(); 40 41 list($dbVersionStruct, $dbVersionStructpublish) = $this->getDbVersions($sqlite); 42 43 // check if struct has required version 44 if ($dbVersionStruct < self::MIN_DB_STRUCT) { 45 throw new Exception('Plugin struct is outdated. Minimum required database version is ' . self::MIN_DB_STRUCT); 46 } 47 48 // check whether we are already up-to-date 49 $latestVersion = $this->getLatestVersion(); 50 if (isset($dbVersionStructpublish) && (int) $dbVersionStructpublish >= $latestVersion) { 51 return true; 52 } 53 54 // check whether we have any pending migrations 55 $pending = range(($dbVersionStructpublish ?: 0) + 1, $latestVersion); 56 if (empty($pending)) { 57 return true; 58 } 59 60 // execute the migrations 61 $ok = true; 62 63 foreach ($pending as $version) { 64 $call = 'migration' . $version; 65 $ok = $ok && $this->$call($sqlite); 66 } 67 68 // update migration status in struct database 69 if ($ok) { 70 $sql = "REPLACE INTO opts (val,opt) VALUES ($version,'dbversion_structpublish')"; 71 $ok = $ok && $sqlite->query($sql); 72 } 73 74 return $ok; 75 } 76 77 /** 78 * Read the current versions for struct and struct publish from the database 79 * 80 * @param \dokuwiki\plugin\sqlite\SQLiteDB $sqlite 81 * @return array [structversion, structpublishversion] 82 */ 83 protected function getDbVersions($sqlite) 84 { 85 $dbVersionStruct = null; 86 $dbVersionStructpublish = null; 87 88 $sql = 'SELECT opt, val FROM opts WHERE opt=? OR opt=?'; 89 $vals = $sqlite->queryAll($sql, ['dbversion', 'dbversion_structpublish']); 90 91 foreach ($vals as $val) { 92 if ($val['opt'] === 'dbversion') { 93 $dbVersionStruct = $val['val']; 94 } 95 if ($val['opt'] === 'dbversion_structpublish') { 96 $dbVersionStructpublish = $val['val']; 97 } 98 } 99 return [$dbVersionStruct, $dbVersionStructpublish]; 100 } 101 102 /** 103 * @return int 104 */ 105 protected function getLatestVersion() 106 { 107 return (int) trim(file_get_contents(DOKU_PLUGIN . 'structpublish/db/latest.version', false)); 108 } 109 110 /** 111 * Database setup 112 * 113 * @param \dokuwiki\plugin\sqlite\SQLiteDB $sqlite 114 * @return bool 115 */ 116 protected function migration1($sqlite) 117 { 118 $file = DOKU_PLUGIN . 'structpublish/db/json/structpublish0001.struct.json'; 119 $schemaJson = file_get_contents($file); 120 $importer = new \dokuwiki\plugin\struct\meta\SchemaImporter('structpublish', $schemaJson); 121 $ok = (bool) $importer->build(); 122 123 if ($ok) { 124 $sql = io_readFile(DOKU_PLUGIN . 'structpublish/db/update0001.sql', false); 125 $sqlArr = Tools::SQLstring2array($sql); 126 foreach ($sqlArr as $sql) { 127 $ok = $ok && $sqlite->query($sql); 128 } 129 } 130 131 return $ok; 132 } 133 134 /** 135 * Reset 'latest' flag to 0 for all rows except actually latest ones 136 * for each pid / status combination. 137 * 138 * @param \dokuwiki\plugin\sqlite\SQLiteDB $sqlite 139 * @return bool 140 */ 141 protected function migration2($sqlite) 142 { 143 $sql = "SELECT rid, pid, latest, col1, max(col4) FROM $this->table GROUP BY pid, col1"; 144 $latest = $sqlite->queryAll($sql); 145 $rids = array_column($latest, 'rid'); 146 147 $sql = "UPDATE $this->table SET latest = 0 WHERE rid NOT IN (" . implode(', ', $rids) . ')'; 148 149 return (bool) $sqlite->query($sql); 150 } 151} 152