xref: /plugin/struct/action/move.php (revision 2cbf895156c26ec5249eb63cc4686102eb02e7ba)
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        // prepare work
50        $this->db->query('BEGIN TRANSACTION');
51
52        // general update of our meta tables
53        $this->updateDataTablePIDs($old, $new);
54        $this->updateAssignments($old, $new);
55        $this->updateTitles($old, $new);
56
57        // apply updates to all columns in all schemas depending on type
58        $schemas = Schema::getAll();
59        foreach($schemas as $table) {
60            $schema = new Schema($table);
61            foreach($schema->getColumns() as $col) {
62                switch(get_class($col->getType())) {
63                    case Page::class:
64                        $this->updateColumnPage($schema, $col, $old, $new);
65                        break;
66                    case Lookup::class:
67                        $this->updateColumnLookup($schema, $col, $old, $new);
68                        break;
69                }
70            }
71        }
72
73        // FIXME we need to update Media Type fields on media move
74
75        // execute everything
76        $ok = $this->db->query('COMMIT TRANSACTION');
77        if(!$ok) {
78            $this->db->query('ROLLBACK TRANSACTION');
79            return false;
80        }
81
82        return true;
83    }
84
85    /**
86     * Update the pid column of ALL data tables
87     *
88     * (we don't trust the assigments are still there)
89     *
90     * @param string $old old page id
91     * @param string $new new page id
92     */
93    protected function updateDataTablePIDs($old, $new) {
94        foreach(Schema::getAll('page') as $tbl) {
95            /** @noinspection SqlResolve */
96            $sql = "UPDATE data_$tbl SET pid = ? WHERE pid = ?";
97            $this->db->query($sql, array($new, $old));
98
99            /** @noinspection SqlResolve */
100            $sql = "UPDATE multi_$tbl SET pid = ? WHERE pid = ?";
101            $this->db->query($sql, array($new, $old));
102        }
103    }
104
105    /**
106     * Update the page-schema assignments
107     *
108     * @param string $old old page id
109     * @param string $new new page id
110     */
111    protected function updateAssignments($old, $new) {
112        // assignments
113        $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?";
114        $this->db->query($sql, array($new, $old));
115        // make sure assignments still match patterns;
116        $assignments = Assignments::getInstance();
117        $assignments->reevaluatePageAssignments($new);
118    }
119
120    /**
121     * Update the Title information for the moved page
122     *
123     * @param string $old old page id
124     * @param string $new new page id
125     */
126    protected function updateTitles($old, $new) {
127        $sql = "UPDATE titles SET pid = ? WHERE pid = ?";
128        $this->db->query($sql, array($new, $old));
129    }
130
131    /**
132     * Update a Page type column
133     *
134     * @param Schema $schema
135     * @param Column $col
136     * @param string $old old page id
137     * @param string $new new page id
138     */
139    protected function updateColumnPage(Schema $schema, Column $col, $old, $new) {
140        $colref = $col->getColref();
141        $table = $schema->getTable();
142
143        if($col->isMulti()) {
144            /** @noinspection SqlResolve */
145            $sql = "UPDATE multi_$table
146                               SET value = REPLACE(value, ?, ?)
147                             WHERE value LIKE ?
148                               AND colref = $colref
149                               AND latest = 1";
150
151        } else {
152            /** @noinspection SqlResolve */
153            $sql = "UPDATE data_$table
154                               SET col$colref = REPLACE(col$colref, ?, ?)
155                             WHERE col$colref LIKE ?
156                               AND latest = 1";
157        }
158        $this->db->query($sql, $old, $new, $old); // exact match
159        $this->db->query($sql, $old, $new, "$old#%"); // match with hashes
160    }
161
162    /**
163     * Update a Lookup type column
164     *
165     * Lookups contain a page id when the referenced schema is a data schema
166     *
167     * @param Schema $schema
168     * @param Column $col
169     * @param string $old old page id
170     * @param string $new new page id
171     */
172    protected function updateColumnLookup(Schema $schema, Column $col, $old, $new) {
173        $tconf = $col->getType()->getConfig();
174        $ref = new Schema($tconf['schema']);
175        if(!$ref->getId()) return; // this schema does not exist
176        if($ref->isLookup()) return; // a lookup is referenced, nothing to do
177
178        // after the checks it's basically the same as a Page type column
179        $this->updateColumnPage($schema, $col, $old, $new);
180    }
181}
182