xref: /plugin/struct/action/move.php (revision 79b29326ae29dcbf2571b932f1b531c400b9460b) !
10173e75dSAndreas Gohr<?php
2d6d97f60SAnna Dabrowska
30173e75dSAndreas Gohr/**
40173e75dSAndreas Gohr * DokuWiki Plugin struct (Action Component)
50173e75dSAndreas Gohr *
60173e75dSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
70173e75dSAndreas Gohr * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
80173e75dSAndreas Gohr */
90173e75dSAndreas Gohr
10ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Assignments;
115a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\meta\Column;
12ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Schema;
135a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Lookup;
14aa4884afSAndreas Gohruse dokuwiki\plugin\struct\types\Media;
155a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Page;
160173e75dSAndreas Gohr
17d6d97f60SAnna Dabrowskaclass action_plugin_struct_move extends DokuWiki_Action_Plugin
18d6d97f60SAnna Dabrowska{
195a1a3bb1SAndreas Gohr    /** @var helper_plugin_sqlite */
205a1a3bb1SAndreas Gohr    protected $db = null;
215a1a3bb1SAndreas Gohr
220173e75dSAndreas Gohr    /**
230173e75dSAndreas Gohr     * Registers a callback function for a given event
240173e75dSAndreas Gohr     *
250173e75dSAndreas Gohr     * @param Doku_Event_Handler $controller DokuWiki's event controller object
260173e75dSAndreas Gohr     * @return void
270173e75dSAndreas Gohr     */
28d6d97f60SAnna Dabrowska    public function register(Doku_Event_Handler $controller)
29d6d97f60SAnna Dabrowska    {
30748e747fSAnna Dabrowska        $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handleMove', true);
31748e747fSAnna Dabrowska        $controller->register_hook('PLUGIN_MOVE_MEDIA_RENAME', 'AFTER', $this, 'handleMove', false);
320173e75dSAndreas Gohr    }
330173e75dSAndreas Gohr
340173e75dSAndreas Gohr    /**
355b808f9fSAnna Dabrowska     * Renames all occurrences of a page ID in the database
360173e75dSAndreas Gohr     *
370173e75dSAndreas Gohr     * @param Doku_Event $event event object by reference
38aa4884afSAndreas Gohr     * @param bool $ispage is this a page move operation?
390173e75dSAndreas Gohr     * @return bool
400173e75dSAndreas Gohr     */
41748e747fSAnna Dabrowska    public function handleMove(Doku_Event $event, $ispage)
42d6d97f60SAnna Dabrowska    {
430173e75dSAndreas Gohr        /** @var helper_plugin_struct_db $hlp */
440173e75dSAndreas Gohr        $hlp = plugin_load('helper', 'struct_db');
455a1a3bb1SAndreas Gohr        $this->db = $hlp->getDB(false);
465a1a3bb1SAndreas Gohr        if (!$this->db) return false;
470173e75dSAndreas Gohr        $old = $event->data['src_id'];
480173e75dSAndreas Gohr        $new = $event->data['dst_id'];
490173e75dSAndreas Gohr
502cbf8951SAndreas Gohr        // prepare work
512cbf8951SAndreas Gohr        $this->db->query('BEGIN TRANSACTION');
522cbf8951SAndreas Gohr
535a1a3bb1SAndreas Gohr        // general update of our meta tables
54aa4884afSAndreas Gohr        if ($ispage) {
555a1a3bb1SAndreas Gohr            $this->updateDataTablePIDs($old, $new);
565a1a3bb1SAndreas Gohr            $this->updateAssignments($old, $new);
575a1a3bb1SAndreas Gohr            $this->updateTitles($old, $new);
58aa4884afSAndreas Gohr        }
5907e48105SAndreas Gohr
605a1a3bb1SAndreas Gohr        // apply updates to all columns in all schemas depending on type
615a1a3bb1SAndreas Gohr        $schemas = Schema::getAll();
625a1a3bb1SAndreas Gohr        foreach ($schemas as $table) {
635a1a3bb1SAndreas Gohr            $schema = new Schema($table);
645a1a3bb1SAndreas Gohr            foreach ($schema->getColumns() as $col) {
65aa4884afSAndreas Gohr                if ($ispage) {
665a1a3bb1SAndreas Gohr                    switch (get_class($col->getType())) {
675a1a3bb1SAndreas Gohr                        case Page::class:
68aa4884afSAndreas Gohr                            $this->updateColumnID($schema, $col, $old, $new, true);
695a1a3bb1SAndreas Gohr                            break;
705a1a3bb1SAndreas Gohr                        case Lookup::class:
715a1a3bb1SAndreas Gohr                            $this->updateColumnLookup($schema, $col, $old, $new);
725a1a3bb1SAndreas Gohr                            break;
730173e75dSAndreas Gohr                    }
74aa4884afSAndreas Gohr                } else {
75aa4884afSAndreas Gohr                    switch (get_class($col->getType())) {
76aa4884afSAndreas Gohr                        case Media::class:
77aa4884afSAndreas Gohr                            $this->updateColumnID($schema, $col, $old, $new);
78aa4884afSAndreas Gohr                            break;
795a1a3bb1SAndreas Gohr                    }
805a1a3bb1SAndreas Gohr                }
81aa4884afSAndreas Gohr            }
82aa4884afSAndreas Gohr        }
832cbf8951SAndreas Gohr
842cbf8951SAndreas Gohr        // execute everything
852cbf8951SAndreas Gohr        $ok = $this->db->query('COMMIT TRANSACTION');
862cbf8951SAndreas Gohr        if (!$ok) {
872cbf8951SAndreas Gohr            $this->db->query('ROLLBACK TRANSACTION');
882cbf8951SAndreas Gohr            return false;
892cbf8951SAndreas Gohr        }
9007e48105SAndreas Gohr
910173e75dSAndreas Gohr        return true;
920173e75dSAndreas Gohr    }
9307e48105SAndreas Gohr
9407e48105SAndreas Gohr    /**
955a1a3bb1SAndreas Gohr     * Update the pid column of ALL data tables
9607e48105SAndreas Gohr     *
975a1a3bb1SAndreas Gohr     * (we don't trust the assigments are still there)
985a1a3bb1SAndreas Gohr     *
995a1a3bb1SAndreas Gohr     * @param string $old old page id
1005a1a3bb1SAndreas Gohr     * @param string $new new page id
10107e48105SAndreas Gohr     */
102d6d97f60SAnna Dabrowska    protected function updateDataTablePIDs($old, $new)
103d6d97f60SAnna Dabrowska    {
1045b808f9fSAnna Dabrowska        foreach (Schema::getAll() as $tbl) {
1055a1a3bb1SAndreas Gohr            /** @noinspection SqlResolve */
1065a1a3bb1SAndreas Gohr            $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?";
1075a1a3bb1SAndreas Gohr            $this->db->query($sql, array($new, $old));
10807e48105SAndreas Gohr
1095a1a3bb1SAndreas Gohr            /** @noinspection SqlResolve */
1105a1a3bb1SAndreas Gohr            $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?";
1115a1a3bb1SAndreas Gohr            $this->db->query($sql, array($new, $old));
1125a1a3bb1SAndreas Gohr        }
1135a1a3bb1SAndreas Gohr    }
11407e48105SAndreas Gohr
1155a1a3bb1SAndreas Gohr    /**
1165a1a3bb1SAndreas Gohr     * Update the page-schema assignments
1175a1a3bb1SAndreas Gohr     *
1185a1a3bb1SAndreas Gohr     * @param string $old old page id
1195a1a3bb1SAndreas Gohr     * @param string $new new page id
1205a1a3bb1SAndreas Gohr     */
121d6d97f60SAnna Dabrowska    protected function updateAssignments($old, $new)
122d6d97f60SAnna Dabrowska    {
1235a1a3bb1SAndreas Gohr        // assignments
1245a1a3bb1SAndreas Gohr        $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?";
1255a1a3bb1SAndreas Gohr        $this->db->query($sql, array($new, $old));
1265a1a3bb1SAndreas Gohr        // make sure assignments still match patterns;
1275a1a3bb1SAndreas Gohr        $assignments = Assignments::getInstance();
1285a1a3bb1SAndreas Gohr        $assignments->reevaluatePageAssignments($new);
1295a1a3bb1SAndreas Gohr    }
1305a1a3bb1SAndreas Gohr
1315a1a3bb1SAndreas Gohr    /**
1325a1a3bb1SAndreas Gohr     * Update the Title information for the moved page
1335a1a3bb1SAndreas Gohr     *
1345a1a3bb1SAndreas Gohr     * @param string $old old page id
1355a1a3bb1SAndreas Gohr     * @param string $new new page id
1365a1a3bb1SAndreas Gohr     */
137d6d97f60SAnna Dabrowska    protected function updateTitles($old, $new)
138d6d97f60SAnna Dabrowska    {
1395a1a3bb1SAndreas Gohr        $sql = "UPDATE titles SET pid = ? WHERE pid = ?";
1405a1a3bb1SAndreas Gohr        $this->db->query($sql, array($new, $old));
1415a1a3bb1SAndreas Gohr    }
1425a1a3bb1SAndreas Gohr
1435a1a3bb1SAndreas Gohr    /**
144aa4884afSAndreas Gohr     * Update the ID in a given column
1455a1a3bb1SAndreas Gohr     *
1465a1a3bb1SAndreas Gohr     * @param Schema $schema
1475a1a3bb1SAndreas Gohr     * @param Column $col
1485a1a3bb1SAndreas Gohr     * @param string $old old page id
1495a1a3bb1SAndreas Gohr     * @param string $new new page id
150aa4884afSAndreas Gohr     * @param bool $hashes could the ID have a hash part? (for Page type)
1515a1a3bb1SAndreas Gohr     */
152d6d97f60SAnna Dabrowska    protected function updateColumnID(Schema $schema, Column $col, $old, $new, $hashes = false)
153d6d97f60SAnna Dabrowska    {
15407e48105SAndreas Gohr        $colref = $col->getColref();
1555a1a3bb1SAndreas Gohr        $table = $schema->getTable();
1565a1a3bb1SAndreas Gohr
15707e48105SAndreas Gohr        if ($col->isMulti()) {
15807e48105SAndreas Gohr            /** @noinspection SqlResolve */
15907e48105SAndreas Gohr            $sql = "UPDATE multi_$table
16007e48105SAndreas Gohr                               SET value = REPLACE(value, ?, ?)
16107e48105SAndreas Gohr                             WHERE value LIKE ?
16207e48105SAndreas Gohr                               AND colref = $colref
16307e48105SAndreas Gohr                               AND latest = 1";
16407e48105SAndreas Gohr        } else {
16507e48105SAndreas Gohr            /** @noinspection SqlResolve */
16607e48105SAndreas Gohr            $sql = "UPDATE data_$table
16707e48105SAndreas Gohr                               SET col$colref = REPLACE(col$colref, ?, ?)
16807e48105SAndreas Gohr                             WHERE col$colref LIKE ?
16907e48105SAndreas Gohr                               AND latest = 1";
17007e48105SAndreas Gohr        }
171*79b29326SAnna Dabrowska        $this->db->query($sql, [$old, $new, $old]); // exact match
172aa4884afSAndreas Gohr        if ($hashes) {
173*79b29326SAnna Dabrowska            $this->db->query($sql, [$old, $new, "$old#%"]); // match with hashes
17407e48105SAndreas Gohr        }
175dd40f4d1SAnna Dabrowska        if (get_class($col->getType()) === Lookup::class) {
176*79b29326SAnna Dabrowska            $this->db->query($sql, [$old, $new, "[\"$old\",%]"]); // match JSON string
177dd40f4d1SAnna Dabrowska            if ($hashes) {
178*79b29326SAnna Dabrowska                $this->db->query($sql, [$old, $new, "[\"$old#%\",%]"]); // match JSON string with hash
179dd40f4d1SAnna Dabrowska            }
180dd40f4d1SAnna Dabrowska        }
181aa4884afSAndreas Gohr    }
1825a1a3bb1SAndreas Gohr
1835a1a3bb1SAndreas Gohr    /**
1845a1a3bb1SAndreas Gohr     * Update a Lookup type column
1855a1a3bb1SAndreas Gohr     *
1865a1a3bb1SAndreas Gohr     * Lookups contain a page id when the referenced schema is a data schema
1875a1a3bb1SAndreas Gohr     *
1885a1a3bb1SAndreas Gohr     * @param Schema $schema
1895a1a3bb1SAndreas Gohr     * @param Column $col
1905a1a3bb1SAndreas Gohr     * @param string $old old page id
1915a1a3bb1SAndreas Gohr     * @param string $new new page id
1925a1a3bb1SAndreas Gohr     */
193d6d97f60SAnna Dabrowska    protected function updateColumnLookup(Schema $schema, Column $col, $old, $new)
194d6d97f60SAnna Dabrowska    {
1955a1a3bb1SAndreas Gohr        $tconf = $col->getType()->getConfig();
1965a1a3bb1SAndreas Gohr        $ref = new Schema($tconf['schema']);
1975a1a3bb1SAndreas Gohr        if (!$ref->getId()) return; // this schema does not exist
1980ceefd5cSAnna Dabrowska        if (!$ref->getTimeStamp()) return; // a lookup is referenced, nothing to do
19910575566SAnna Dabrowska        $this->updateColumnID($schema, $col, $old, $new);
20007e48105SAndreas Gohr    }
2010173e75dSAndreas Gohr}
202