187106851SAnna Dabrowska<?php 287106851SAnna Dabrowska 3f734c62fSAnna Dabrowskause dokuwiki\plugin\sqlite\Tools; 4f734c62fSAnna Dabrowska 587106851SAnna Dabrowskaclass action_plugin_structpublish_migration extends DokuWiki_Action_Plugin 687106851SAnna Dabrowska{ 7bcee0e72SAnna Dabrowska const MIN_DB_STRUCT = 19; 8bcee0e72SAnna Dabrowska 9d93c534aSAnna Dabrowska /** @var string */ 10d93c534aSAnna Dabrowska protected $table = 'data_structpublish'; 11d93c534aSAnna Dabrowska 1287106851SAnna Dabrowska /** 1387106851SAnna Dabrowska * @inheritDoc 1487106851SAnna Dabrowska */ 1587106851SAnna Dabrowska public function register(Doku_Event_Handler $controller) 1687106851SAnna Dabrowska { 1787106851SAnna Dabrowska $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleMigrations'); 1887106851SAnna Dabrowska } 1987106851SAnna Dabrowska 2087106851SAnna Dabrowska /** 21d93c534aSAnna Dabrowska * Call our custom migrations. We do not use our own database, 22d93c534aSAnna Dabrowska * so we cannot use the mechanism in sqlite init() 23d93c534aSAnna Dabrowska * which processes updateXXXX.sql files 2487106851SAnna Dabrowska * 2587106851SAnna Dabrowska * @param Doku_Event $event 2687106851SAnna Dabrowska * @return bool 278b0ba635SAndreas Gohr * @throws Exception 2887106851SAnna Dabrowska */ 2987106851SAnna Dabrowska public function handleMigrations(Doku_Event $event) 3087106851SAnna Dabrowska { 3187106851SAnna Dabrowska /** @var \helper_plugin_struct_db $helper */ 3287106851SAnna Dabrowska $helper = plugin_load('helper', 'struct_db'); 33bcee0e72SAnna Dabrowska 34bcee0e72SAnna Dabrowska // abort if struct is not installed 35bcee0e72SAnna Dabrowska if (!$helper) { 36bcee0e72SAnna Dabrowska throw new Exception('Plugin struct is required!'); 37bcee0e72SAnna Dabrowska } 38bcee0e72SAnna Dabrowska 3987106851SAnna Dabrowska $sqlite = $helper->getDB(); 4087106851SAnna Dabrowska 4187106851SAnna Dabrowska list($dbVersionStruct, $dbVersionStructpublish) = $this->getDbVersions($sqlite); 42bcee0e72SAnna Dabrowska 43bcee0e72SAnna Dabrowska // check if struct has required version 44bcee0e72SAnna Dabrowska if ($dbVersionStruct < self::MIN_DB_STRUCT) { 458b0ba635SAndreas Gohr throw new Exception('Plugin struct is outdated. Minimum required database version is ' . self::MIN_DB_STRUCT); 46bcee0e72SAnna Dabrowska } 47bcee0e72SAnna Dabrowska 48bcee0e72SAnna Dabrowska // check whether we are already up-to-date 49bcee0e72SAnna Dabrowska $latestVersion = $this->getLatestVersion(); 50bcee0e72SAnna Dabrowska if (isset($dbVersionStructpublish) && (int) $dbVersionStructpublish >= $latestVersion) { 518b0ba635SAndreas Gohr return true; 5287106851SAnna Dabrowska } 5387106851SAnna Dabrowska 54bcee0e72SAnna Dabrowska // check whether we have any pending migrations 55d93c534aSAnna Dabrowska $pending = range(($dbVersionStructpublish ?: 0) + 1, $latestVersion); 5687106851SAnna Dabrowska if (empty($pending)) { 578b0ba635SAndreas Gohr return true; 5887106851SAnna Dabrowska } 5987106851SAnna Dabrowska 6087106851SAnna Dabrowska // execute the migrations 618b0ba635SAndreas Gohr $ok = true; 62d93c534aSAnna Dabrowska 6387106851SAnna Dabrowska foreach ($pending as $version) { 6487106851SAnna Dabrowska $call = 'migration' . $version; 6587106851SAnna Dabrowska $ok = $ok && $this->$call($sqlite); 6687106851SAnna Dabrowska } 6787106851SAnna Dabrowska 68d93c534aSAnna Dabrowska // update migration status in struct database 69d93c534aSAnna Dabrowska if ($ok) { 70d93c534aSAnna Dabrowska $sql = "REPLACE INTO opts (val,opt) VALUES ($version,'dbversion_structpublish')"; 71d93c534aSAnna Dabrowska $ok = $ok && $sqlite->query($sql); 72d93c534aSAnna Dabrowska } 73d93c534aSAnna Dabrowska 7487106851SAnna Dabrowska return $ok; 7587106851SAnna Dabrowska } 7687106851SAnna Dabrowska 7787106851SAnna Dabrowska /** 788b0ba635SAndreas Gohr * Read the current versions for struct and struct publish from the database 798b0ba635SAndreas Gohr * 80f734c62fSAnna Dabrowska * @param \dokuwiki\plugin\sqlite\SQLiteDB $sqlite 818b0ba635SAndreas Gohr * @return array [structversion, structpublishversion] 8287106851SAnna Dabrowska */ 8387106851SAnna Dabrowska protected function getDbVersions($sqlite) 8487106851SAnna Dabrowska { 8587106851SAnna Dabrowska $dbVersionStruct = null; 8687106851SAnna Dabrowska $dbVersionStructpublish = null; 8787106851SAnna Dabrowska 8887106851SAnna Dabrowska $sql = 'SELECT opt, val FROM opts WHERE opt=? OR opt=?'; 89f734c62fSAnna Dabrowska $vals = $sqlite->queryAll($sql, ['dbversion', 'dbversion_structpublish']); 9087106851SAnna Dabrowska 9187106851SAnna Dabrowska foreach ($vals as $val) { 9287106851SAnna Dabrowska if ($val['opt'] === 'dbversion') { 9387106851SAnna Dabrowska $dbVersionStruct = $val['val']; 9487106851SAnna Dabrowska } 9587106851SAnna Dabrowska if ($val['opt'] === 'dbversion_structpublish') { 9687106851SAnna Dabrowska $dbVersionStructpublish = $val['val']; 9787106851SAnna Dabrowska } 9887106851SAnna Dabrowska } 9987106851SAnna Dabrowska return [$dbVersionStruct, $dbVersionStructpublish]; 10087106851SAnna Dabrowska } 10187106851SAnna Dabrowska 10287106851SAnna Dabrowska /** 103bcee0e72SAnna Dabrowska * @return int 104bcee0e72SAnna Dabrowska */ 105bcee0e72SAnna Dabrowska protected function getLatestVersion() 106bcee0e72SAnna Dabrowska { 107bcee0e72SAnna Dabrowska return (int) trim(file_get_contents(DOKU_PLUGIN . 'structpublish/db/latest.version', false)); 108bcee0e72SAnna Dabrowska } 109bcee0e72SAnna Dabrowska 110bcee0e72SAnna Dabrowska /** 111bcee0e72SAnna Dabrowska * Database setup 11287106851SAnna Dabrowska * 113f734c62fSAnna Dabrowska * @param \dokuwiki\plugin\sqlite\SQLiteDB $sqlite 11487106851SAnna Dabrowska * @return bool 11587106851SAnna Dabrowska */ 116bcee0e72SAnna Dabrowska protected function migration1($sqlite) 11787106851SAnna Dabrowska { 1187ada453dSAnna Dabrowska $file = DOKU_PLUGIN . 'structpublish/db/json/structpublish0001.struct.json'; 1197ada453dSAnna Dabrowska $schemaJson = file_get_contents($file); 1207ada453dSAnna Dabrowska $importer = new \dokuwiki\plugin\struct\meta\SchemaImporter('structpublish', $schemaJson); 1217ada453dSAnna Dabrowska $ok = (bool) $importer->build(); 1227ada453dSAnna Dabrowska 1237ada453dSAnna Dabrowska if ($ok) { 124bcee0e72SAnna Dabrowska $sql = io_readFile(DOKU_PLUGIN . 'structpublish/db/update0001.sql', false); 125f734c62fSAnna Dabrowska $sqlArr = Tools::SQLstring2array($sql); 126f734c62fSAnna Dabrowska foreach ($sqlArr as $sql) { 127f734c62fSAnna Dabrowska $ok = $ok && $sqlite->query($sql); 128f734c62fSAnna Dabrowska } 129f734c62fSAnna Dabrowska } 130677c897aSAnna Dabrowska 131677c897aSAnna Dabrowska return $ok; 13287106851SAnna Dabrowska } 133d93c534aSAnna Dabrowska 134d93c534aSAnna Dabrowska /** 135d93c534aSAnna Dabrowska * Reset 'latest' flag to 0 for all rows except actually latest ones 136d93c534aSAnna Dabrowska * for each pid / status combination. 137d93c534aSAnna Dabrowska * 138d93c534aSAnna Dabrowska * @param \dokuwiki\plugin\sqlite\SQLiteDB $sqlite 139d93c534aSAnna Dabrowska * @return bool 140d93c534aSAnna Dabrowska */ 141d93c534aSAnna Dabrowska protected function migration2($sqlite) 142d93c534aSAnna Dabrowska { 143d93c534aSAnna Dabrowska $sql = "SELECT rid, pid, latest, col1, max(col4) FROM $this->table GROUP BY pid, col1"; 144d93c534aSAnna Dabrowska $latest = $sqlite->queryAll($sql); 145d93c534aSAnna Dabrowska $rids = array_column($latest, 'rid'); 146d93c534aSAnna Dabrowska 147d93c534aSAnna Dabrowska $sql = "UPDATE $this->table SET latest = 0 WHERE rid NOT IN (" . implode(', ', $rids) . ')'; 148d93c534aSAnna Dabrowska 149d93c534aSAnna Dabrowska return (bool) $sqlite->query($sql); 150d93c534aSAnna Dabrowska } 151*c4618b6cSAnna Dabrowska 152*c4618b6cSAnna Dabrowska /** 153*c4618b6cSAnna Dabrowska * Set 'latest' flag to 0 for all rows except actually latest ones 154*c4618b6cSAnna Dabrowska * for each page, 155*c4618b6cSAnna Dabrowska * 156*c4618b6cSAnna Dabrowska * @param \dokuwiki\plugin\sqlite\SQLiteDB $sqlite 157*c4618b6cSAnna Dabrowska * @return bool 158*c4618b6cSAnna Dabrowska */ 159*c4618b6cSAnna Dabrowska protected function migration3($sqlite) 160*c4618b6cSAnna Dabrowska { 161*c4618b6cSAnna Dabrowska $sql = "WITH cte AS ( 162*c4618b6cSAnna Dabrowska SELECT rid, pid, col1 AS status, col4 as rev, 163*c4618b6cSAnna Dabrowska rank() OVER ( PARTITION BY pid 164*c4618b6cSAnna Dabrowska ORDER BY col4 DESC, col1 = 'draft', col1 = 'approved', col1 = 'published' 165*c4618b6cSAnna Dabrowska ) AS r 166*c4618b6cSAnna Dabrowska FROM data_structpublish 167*c4618b6cSAnna Dabrowska ) 168*c4618b6cSAnna Dabrowska SELECT rid, pid, status, rev 169*c4618b6cSAnna Dabrowska FROM cte 170*c4618b6cSAnna Dabrowska WHERE r = 1 171*c4618b6cSAnna Dabrowska ORDER BY pid ASC;"; 172*c4618b6cSAnna Dabrowska 173*c4618b6cSAnna Dabrowska $latest = $sqlite->queryAll($sql); 174*c4618b6cSAnna Dabrowska $rids = array_column($latest, 'rid'); 175*c4618b6cSAnna Dabrowska 176*c4618b6cSAnna Dabrowska $sql = "UPDATE $this->table SET latest = 0 WHERE rid NOT IN (" . implode(', ', $rids) . ')'; 177*c4618b6cSAnna Dabrowska 178*c4618b6cSAnna Dabrowska return (bool) $sqlite->query($sql); 179*c4618b6cSAnna Dabrowska } 18087106851SAnna Dabrowska} 181