xref: /plugin/structpublish/action/migration.php (revision e394901a0f7c5b3f8d056c0f4d754d974f4f8413)
1<?php
2
3class action_plugin_structpublish_migration extends DokuWiki_Action_Plugin
4{
5    /**
6     * @inheritDoc
7     */
8    public function register(Doku_Event_Handler $controller)
9    {
10        $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'BEFORE', $this, 'handleMigrations');
11        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleMigrations');
12    }
13
14    /**
15     * Call our custom migrations when defined
16     *
17     * @param Doku_Event $event
18     * @return bool
19     */
20    public function handleMigrations(Doku_Event $event)
21    {
22        /** @var \helper_plugin_struct_db $helper */
23        $helper = plugin_load('helper', 'struct_db');
24        $sqlite = $helper->getDB();
25
26        $ok = true;
27
28        // check whether we are already up-to-date
29        list($dbVersionStruct, $dbVersionStructpublish) = $this->getDbVersions($sqlite);
30        if (isset($dbVersionStructpublish) && (string)$dbVersionStructpublish == (string)$dbVersionStruct) {
31            return $ok;
32        }
33
34        // check whether we have any pending migrations for the current version of struct db
35        $pending = array_filter(array_map(function ($version) use ($dbVersionStruct) {
36            return $version >= $dbVersionStruct &&
37            is_callable([$this, "migration$version"]) ? $version : null;
38        }, $this->diffVersions($dbVersionStruct, $dbVersionStructpublish)));
39        if (empty($pending)) {
40            return $ok;
41        }
42
43        // execute the migrations
44        foreach ($pending as $version) {
45            $call = 'migration' . $version;
46            $ok = $ok && $this->$call($sqlite);
47        }
48
49        return $ok;
50    }
51
52    /**
53     * Detect which migrations should be executed. Start conservatively with version 1.
54     *
55     * @param int $dbVersionStruct Current version of struct DB as found in 'opts' table
56     * @param int|null $dbVersionStructpublish Current version in 'opts', may not exist yet
57     * @return int[]
58     */
59    protected function diffVersions($dbVersionStruct, $dbVersionStructpublish)
60    {
61        $pluginDbVersion = $dbVersionStructpublish ?: 1;
62        return range($pluginDbVersion, $dbVersionStruct);
63    }
64
65    /**
66     * @param $sqlite
67     * @return array
68     */
69    protected function getDbVersions($sqlite)
70    {
71        $dbVersionStruct = null;
72        $dbVersionStructpublish = null;
73
74        $sql = 'SELECT opt, val FROM opts WHERE opt=? OR opt=?';
75        $res = $sqlite->query($sql, 'dbversion', 'dbversion_structpublish');
76        $vals = $sqlite->res2arr($res);
77
78        foreach ($vals as $val) {
79            if ($val['opt'] === 'dbversion') {
80                $dbVersionStruct = $val['val'];
81            }
82            if ($val['opt'] === 'dbversion_structpublish') {
83                $dbVersionStructpublish = $val['val'];
84            }
85        }
86        return [$dbVersionStruct, $dbVersionStructpublish];
87    }
88
89    /**
90     * Database setup, required struct db version is 19
91     *
92     * @param helper_plugin_sqlite $sqlite
93     * @return bool
94     */
95    protected function migration19($sqlite)
96    {
97        $sql = io_readFile(DOKU_PLUGIN . 'structpublish/db/struct/update0019.sql', false);
98
99        $sql = $sqlite->SQLstring2array($sql);
100        array_unshift($sql, 'BEGIN TRANSACTION');
101        array_push($sql, "INSERT OR REPLACE INTO opts (val,opt) VALUES (19,'dbversion_structpublish')");
102        array_push($sql, "COMMIT TRANSACTION");
103        return $sqlite->doTransaction($sql);
104    }
105}
106