xref: /plugin/struct/action/move.php (revision 5e29103a15bd9873f422f66a6a5239b6aec4651e)
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
107234bfb1Ssplitbrainuse dokuwiki\Extension\ActionPlugin;
117234bfb1Ssplitbrainuse dokuwiki\Extension\EventHandler;
127234bfb1Ssplitbrainuse dokuwiki\Extension\Event;
137234bfb1Ssplitbrainuse dokuwiki\plugin\sqlite\SQLiteDB;
14ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Assignments;
155a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\meta\Column;
16ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Schema;
175a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Lookup;
18aa4884afSAndreas Gohruse dokuwiki\plugin\struct\types\Media;
195a1a3bb1SAndreas Gohruse dokuwiki\plugin\struct\types\Page;
200173e75dSAndreas Gohr
217234bfb1Ssplitbrainclass action_plugin_struct_move extends ActionPlugin
22d6d97f60SAnna Dabrowska{
235a1a3bb1SAndreas Gohr    /** @var helper_plugin_sqlite */
247234bfb1Ssplitbrain    protected $db;
255a1a3bb1SAndreas Gohr
260173e75dSAndreas Gohr    /**
270173e75dSAndreas Gohr     * Registers a callback function for a given event
280173e75dSAndreas Gohr     *
29*5e29103aSannda     * @param EventHandler $controller DokuWiki's event controller object
300173e75dSAndreas Gohr     * @return void
310173e75dSAndreas Gohr     */
327234bfb1Ssplitbrain    public function register(EventHandler $controller)
33d6d97f60SAnna Dabrowska    {
34748e747fSAnna Dabrowska        $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handleMove', true);
35748e747fSAnna Dabrowska        $controller->register_hook('PLUGIN_MOVE_MEDIA_RENAME', 'AFTER', $this, 'handleMove', false);
360173e75dSAndreas Gohr    }
370173e75dSAndreas Gohr
380173e75dSAndreas Gohr    /**
395b808f9fSAnna Dabrowska     * Renames all occurrences of a page ID in the database
400173e75dSAndreas Gohr     *
41*5e29103aSannda     * @param Event $event event object by reference
42aa4884afSAndreas Gohr     * @param bool $ispage is this a page move operation?
430173e75dSAndreas Gohr     * @return bool
440173e75dSAndreas Gohr     */
457234bfb1Ssplitbrain    public function handleMove(Event $event, $ispage)
46d6d97f60SAnna Dabrowska    {
470173e75dSAndreas Gohr        /** @var helper_plugin_struct_db $hlp */
480173e75dSAndreas Gohr        $hlp = plugin_load('helper', 'struct_db');
495a1a3bb1SAndreas Gohr        $this->db = $hlp->getDB(false);
507234bfb1Ssplitbrain        if (!$this->db instanceof SQLiteDB) return false;
510173e75dSAndreas Gohr        $old = $event->data['src_id'];
520173e75dSAndreas Gohr        $new = $event->data['dst_id'];
530173e75dSAndreas Gohr
542cbf8951SAndreas Gohr        // prepare work
552cbf8951SAndreas Gohr        $this->db->query('BEGIN TRANSACTION');
562cbf8951SAndreas Gohr
575a1a3bb1SAndreas Gohr        // general update of our meta tables
58aa4884afSAndreas Gohr        if ($ispage) {
595a1a3bb1SAndreas Gohr            $this->updateDataTablePIDs($old, $new);
605a1a3bb1SAndreas Gohr            $this->updateAssignments($old, $new);
615a1a3bb1SAndreas Gohr            $this->updateTitles($old, $new);
62aa4884afSAndreas Gohr        }
6307e48105SAndreas Gohr
645a1a3bb1SAndreas Gohr        // apply updates to all columns in all schemas depending on type
655a1a3bb1SAndreas Gohr        $schemas = Schema::getAll();
665a1a3bb1SAndreas Gohr        foreach ($schemas as $table) {
675a1a3bb1SAndreas Gohr            $schema = new Schema($table);
685a1a3bb1SAndreas Gohr            foreach ($schema->getColumns() as $col) {
69aa4884afSAndreas Gohr                if ($ispage) {
707234bfb1Ssplitbrain                    if (get_class($col->getType()) == Page::class) {
71aa4884afSAndreas Gohr                        $this->updateColumnID($schema, $col, $old, $new, true);
727234bfb1Ssplitbrain                    } elseif (get_class($col->getType()) == Lookup::class) {
735a1a3bb1SAndreas Gohr                        $this->updateColumnLookup($schema, $col, $old, $new);
740173e75dSAndreas Gohr                    }
757234bfb1Ssplitbrain                } elseif ($col->getType() instanceof Media) {
76aa4884afSAndreas Gohr                    $this->updateColumnID($schema, $col, $old, $new);
775a1a3bb1SAndreas Gohr                }
78aa4884afSAndreas Gohr            }
79aa4884afSAndreas Gohr        }
802cbf8951SAndreas Gohr
812cbf8951SAndreas Gohr        // execute everything
822cbf8951SAndreas Gohr        $ok = $this->db->query('COMMIT TRANSACTION');
832cbf8951SAndreas Gohr        if (!$ok) {
842cbf8951SAndreas Gohr            $this->db->query('ROLLBACK TRANSACTION');
852cbf8951SAndreas Gohr            return false;
862cbf8951SAndreas Gohr        }
8707e48105SAndreas Gohr
880173e75dSAndreas Gohr        return true;
890173e75dSAndreas Gohr    }
9007e48105SAndreas Gohr
9107e48105SAndreas Gohr    /**
925a1a3bb1SAndreas Gohr     * Update the pid column of ALL data tables
9307e48105SAndreas Gohr     *
945a1a3bb1SAndreas Gohr     * (we don't trust the assigments are still there)
955a1a3bb1SAndreas Gohr     *
965a1a3bb1SAndreas Gohr     * @param string $old old page id
975a1a3bb1SAndreas Gohr     * @param string $new new page id
9807e48105SAndreas Gohr     */
99d6d97f60SAnna Dabrowska    protected function updateDataTablePIDs($old, $new)
100d6d97f60SAnna Dabrowska    {
1015b808f9fSAnna Dabrowska        foreach (Schema::getAll() as $tbl) {
1025a1a3bb1SAndreas Gohr            /** @noinspection SqlResolve */
1035a1a3bb1SAndreas Gohr            $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?";
1047234bfb1Ssplitbrain            $this->db->query($sql, [$new, $old]);
10507e48105SAndreas Gohr
1065a1a3bb1SAndreas Gohr            /** @noinspection SqlResolve */
1075a1a3bb1SAndreas Gohr            $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?";
1087234bfb1Ssplitbrain            $this->db->query($sql, [$new, $old]);
1095a1a3bb1SAndreas Gohr        }
1105a1a3bb1SAndreas Gohr    }
11107e48105SAndreas Gohr
1125a1a3bb1SAndreas Gohr    /**
1135a1a3bb1SAndreas Gohr     * Update the page-schema assignments
1145a1a3bb1SAndreas Gohr     *
1155a1a3bb1SAndreas Gohr     * @param string $old old page id
1165a1a3bb1SAndreas Gohr     * @param string $new new page id
1175a1a3bb1SAndreas Gohr     */
118d6d97f60SAnna Dabrowska    protected function updateAssignments($old, $new)
119d6d97f60SAnna Dabrowska    {
1205a1a3bb1SAndreas Gohr        // assignments
1215a1a3bb1SAndreas Gohr        $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?";
1227234bfb1Ssplitbrain        $this->db->query($sql, [$new, $old]);
1235a1a3bb1SAndreas Gohr        // make sure assignments still match patterns;
1245a1a3bb1SAndreas Gohr        $assignments = Assignments::getInstance();
1255a1a3bb1SAndreas Gohr        $assignments->reevaluatePageAssignments($new);
1265a1a3bb1SAndreas Gohr    }
1275a1a3bb1SAndreas Gohr
1285a1a3bb1SAndreas Gohr    /**
1295a1a3bb1SAndreas Gohr     * Update the Title information for the moved page
1305a1a3bb1SAndreas Gohr     *
1315a1a3bb1SAndreas Gohr     * @param string $old old page id
1325a1a3bb1SAndreas Gohr     * @param string $new new page id
1335a1a3bb1SAndreas Gohr     */
134d6d97f60SAnna Dabrowska    protected function updateTitles($old, $new)
135d6d97f60SAnna Dabrowska    {
1365a1a3bb1SAndreas Gohr        $sql = "UPDATE titles SET pid = ? WHERE pid = ?";
1377234bfb1Ssplitbrain        $this->db->query($sql, [$new, $old]);
1385a1a3bb1SAndreas Gohr    }
1395a1a3bb1SAndreas Gohr
1405a1a3bb1SAndreas Gohr    /**
141aa4884afSAndreas Gohr     * Update the ID in a given column
1425a1a3bb1SAndreas Gohr     *
1435a1a3bb1SAndreas Gohr     * @param Schema $schema
1445a1a3bb1SAndreas Gohr     * @param Column $col
1455a1a3bb1SAndreas Gohr     * @param string $old old page id
1465a1a3bb1SAndreas Gohr     * @param string $new new page id
147aa4884afSAndreas Gohr     * @param bool $hashes could the ID have a hash part? (for Page type)
1485a1a3bb1SAndreas Gohr     */
149d6d97f60SAnna Dabrowska    protected function updateColumnID(Schema $schema, Column $col, $old, $new, $hashes = false)
150d6d97f60SAnna Dabrowska    {
15107e48105SAndreas Gohr        $colref = $col->getColref();
1525a1a3bb1SAndreas Gohr        $table = $schema->getTable();
1535a1a3bb1SAndreas Gohr
15407e48105SAndreas Gohr        if ($col->isMulti()) {
15507e48105SAndreas Gohr            /** @noinspection SqlResolve */
15607e48105SAndreas Gohr            $sql = "UPDATE multi_$table
15707e48105SAndreas Gohr                               SET value = REPLACE(value, ?, ?)
15807e48105SAndreas Gohr                             WHERE value LIKE ?
15907e48105SAndreas Gohr                               AND colref = $colref
16007e48105SAndreas Gohr                               AND latest = 1";
16107e48105SAndreas Gohr        } else {
16207e48105SAndreas Gohr            /** @noinspection SqlResolve */
16307e48105SAndreas Gohr            $sql = "UPDATE data_$table
16407e48105SAndreas Gohr                               SET col$colref = REPLACE(col$colref, ?, ?)
16507e48105SAndreas Gohr                             WHERE col$colref LIKE ?
16607e48105SAndreas Gohr                               AND latest = 1";
16707e48105SAndreas Gohr        }
16879b29326SAnna Dabrowska        $this->db->query($sql, [$old, $new, $old]); // exact match
169aa4884afSAndreas Gohr        if ($hashes) {
17079b29326SAnna Dabrowska            $this->db->query($sql, [$old, $new, "$old#%"]); // match with hashes
17107e48105SAndreas Gohr        }
1727234bfb1Ssplitbrain        if ($col->getType() instanceof Lookup) {
17379b29326SAnna Dabrowska            $this->db->query($sql, [$old, $new, "[\"$old\",%]"]); // match JSON string
174dd40f4d1SAnna Dabrowska            if ($hashes) {
17579b29326SAnna Dabrowska                $this->db->query($sql, [$old, $new, "[\"$old#%\",%]"]); // match JSON string with hash
176dd40f4d1SAnna Dabrowska            }
177dd40f4d1SAnna Dabrowska        }
178aa4884afSAndreas Gohr    }
1795a1a3bb1SAndreas Gohr
1805a1a3bb1SAndreas Gohr    /**
1815a1a3bb1SAndreas Gohr     * Update a Lookup type column
1825a1a3bb1SAndreas Gohr     *
1835a1a3bb1SAndreas Gohr     * Lookups contain a page id when the referenced schema is a data schema
1845a1a3bb1SAndreas Gohr     *
1855a1a3bb1SAndreas Gohr     * @param Schema $schema
1865a1a3bb1SAndreas Gohr     * @param Column $col
1875a1a3bb1SAndreas Gohr     * @param string $old old page id
1885a1a3bb1SAndreas Gohr     * @param string $new new page id
1895a1a3bb1SAndreas Gohr     */
190d6d97f60SAnna Dabrowska    protected function updateColumnLookup(Schema $schema, Column $col, $old, $new)
191d6d97f60SAnna Dabrowska    {
1925a1a3bb1SAndreas Gohr        $tconf = $col->getType()->getConfig();
1935a1a3bb1SAndreas Gohr        $ref = new Schema($tconf['schema']);
1945a1a3bb1SAndreas Gohr        if (!$ref->getId()) return; // this schema does not exist
1950ceefd5cSAnna Dabrowska        if (!$ref->getTimeStamp()) return; // a lookup is referenced, nothing to do
19610575566SAnna Dabrowska        $this->updateColumnID($schema, $col, $old, $new);
19707e48105SAndreas Gohr    }
1980173e75dSAndreas Gohr}
199