xref: /plugin/struct/action/move.php (revision 5a1a3bb10c5ddfec65721ddafcfedbfd8f4cee00)
1<?php
2/**
3 * DokuWiki Plugin struct (Action Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
7 */
8
9// must be run within Dokuwiki
10use dokuwiki\plugin\struct\meta\Assignments;
11use dokuwiki\plugin\struct\meta\Column;
12use dokuwiki\plugin\struct\meta\Schema;
13use dokuwiki\plugin\struct\types\Lookup;
14use dokuwiki\plugin\struct\types\Page;
15
16if(!defined('DOKU_INC')) die();
17
18class action_plugin_struct_move extends DokuWiki_Action_Plugin {
19
20    /** @var helper_plugin_sqlite */
21    protected $db = null;
22
23    /**
24     * Registers a callback function for a given event
25     *
26     * @param Doku_Event_Handler $controller DokuWiki's event controller object
27     * @return void
28     */
29    public function register(Doku_Event_Handler $controller) {
30        $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handle_move');
31    }
32
33    /**
34     * Renames all occurances of a page ID in the database
35     *
36     * @param Doku_Event $event event object by reference
37     * @param mixed $param [the parameters passed as fifth argument to register_hook() when this
38     *                           handler was registered]
39     * @return bool
40     */
41    public function handle_move(Doku_Event $event, $param) {
42        /** @var helper_plugin_struct_db $hlp */
43        $hlp = plugin_load('helper', 'struct_db');
44        $this->db = $hlp->getDB(false);
45        if(!$this->db) return false;
46        $old = $event->data['src_id'];
47        $new = $event->data['dst_id'];
48
49        // general update of our meta tables
50        $this->updateDataTablePIDs($old, $new);
51        $this->updateAssignments($old, $new);
52        $this->updateTitles($old, $new);
53
54        // apply updates to all columns in all schemas depending on type
55        $schemas = Schema::getAll();
56        foreach($schemas as $table) {
57            $schema = new Schema($table);
58            foreach($schema->getColumns() as $col) {
59                switch(get_class($col->getType())) {
60                    case Page::class:
61                        $this->updateColumnPage($schema, $col, $old, $new);
62                        break;
63                    case Lookup::class:
64                        $this->updateColumnLookup($schema, $col, $old, $new);
65                        break;
66                }
67            }
68        }
69
70        // FIXME we need to update Media Type fields on media move
71        // FIXME we should wrap all this in a transaction
72
73        return true;
74    }
75
76    /**
77     * Update the pid column of ALL data tables
78     *
79     * (we don't trust the assigments are still there)
80     *
81     * @param string $old old page id
82     * @param string $new new page id
83     */
84    protected function updateDataTablePIDs($old, $new) {
85        foreach(Schema::getAll('page') as $tbl) {
86            /** @noinspection SqlResolve */
87            $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?";
88            $this->db->query($sql, array($new, $old));
89
90            /** @noinspection SqlResolve */
91            $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?";
92            $this->db->query($sql, array($new, $old));
93        }
94    }
95
96    /**
97     * Update the page-schema assignments
98     *
99     * @param string $old old page id
100     * @param string $new new page id
101     */
102    protected function updateAssignments($old, $new) {
103        // assignments
104        $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?";
105        $this->db->query($sql, array($new, $old));
106        // make sure assignments still match patterns;
107        $assignments = Assignments::getInstance();
108        $assignments->reevaluatePageAssignments($new);
109    }
110
111    /**
112     * Update the Title information for the moved page
113     *
114     * @param string $old old page id
115     * @param string $new new page id
116     */
117    protected function updateTitles($old, $new) {
118        $sql = "UPDATE titles SET pid = ? WHERE pid = ?";
119        $this->db->query($sql, array($new, $old));
120    }
121
122    /**
123     * Update a Page type column
124     *
125     * @param Schema $schema
126     * @param Column $col
127     * @param string $old old page id
128     * @param string $new new page id
129     */
130    protected function updateColumnPage(Schema $schema, Column $col, $old, $new) {
131        $colref = $col->getColref();
132        $table = $schema->getTable();
133
134        if($col->isMulti()) {
135            /** @noinspection SqlResolve */
136            $sql = "UPDATE multi_$table
137                               SET value = REPLACE(value, ?, ?)
138                             WHERE value LIKE ?
139                               AND colref = $colref
140                               AND latest = 1";
141
142        } else {
143            /** @noinspection SqlResolve */
144            $sql = "UPDATE data_$table
145                               SET col$colref = REPLACE(col$colref, ?, ?)
146                             WHERE col$colref LIKE ?
147                               AND latest = 1";
148        }
149        $this->db->query($sql, $old, $new, $old); // exact match
150        $this->db->query($sql, $old, $new, "$old#%"); // match with hashes
151    }
152
153    /**
154     * Update a Lookup type column
155     *
156     * Lookups contain a page id when the referenced schema is a data schema
157     *
158     * @param Schema $schema
159     * @param Column $col
160     * @param string $old old page id
161     * @param string $new new page id
162     */
163    protected function updateColumnLookup(Schema $schema, Column $col, $old, $new) {
164        $tconf = $col->getType()->getConfig();
165        $ref = new Schema($tconf['schema']);
166        if(!$ref->getId()) return; // this schema does not exist
167        if($ref->isLookup()) return; // a lookup is referenced, nothing to do
168
169        // after the checks it's basically the same as a Page type column
170        $this->updateColumnPage($schema, $col, $old, $new);
171    }
172}
173