xref: /template/strap/action/linkmove.php (revision 82a60d039cd81033dc8147c27f0a50716b7a5301)
1<?php
2
3require_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
4
5use ComboStrap\Alias;
6use ComboStrap\Aliases;
7use ComboStrap\DatabasePageRow;
8use ComboStrap\ExceptionComboRuntime;
9use ComboStrap\File;
10use ComboStrap\LinkUtility;
11use ComboStrap\LogUtility;
12use ComboStrap\MetadataDbStore;
13use ComboStrap\MetadataDokuWikiStore;
14use ComboStrap\Page;
15use ComboStrap\PageId;
16use ComboStrap\PluginUtility;
17use ComboStrap\Site;
18
19
20/**
21 * Class action_plugin_combo_move
22 * Handle the move of a page in order to update:
23 *   * the link
24 *   * the data in the database
25 */
26class action_plugin_combo_linkmove extends DokuWiki_Action_Plugin
27{
28
29
30    const CANONICAL = "move";
31
32    private static function checkAndSendAMessageIfLockFilePresent(): bool
33    {
34        $lockFile = File::createFromPath(Site::getDataDirectory() . "/locks_plugin_move.lock");
35        if (!$lockFile->exists()) {
36            return false;
37        }
38        $lockFileDateTimeModified = $lockFile->getModifiedTime();
39        $lockFileModifiedTimestamp = $lockFileDateTimeModified->getTimestamp();
40        $now = time();
41
42        $distance = $now - $lockFileModifiedTimestamp;
43        $lockFileAgeInMinute = ($distance) / 60;
44        if ($lockFileAgeInMinute > 5) {
45            LogUtility::msg("The move lockfile ($lockFile) exists and is older than 5 minutes (exactly $lockFileAgeInMinute minutes). If you are no more in a move, you should delete this file otherwise it will disable the move of page and the cache.");
46            return true;
47        }
48        return false;
49    }
50
51    /**
52     * As explained https://www.dokuwiki.org/plugin:move#support_for_other_plugins
53     * @param Doku_Event_Handler $controller
54     */
55    function register(Doku_Event_Handler $controller)
56    {
57
58        /**
59         * To rewrite the page meta in the database
60         */
61        $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'BEFORE', $this, 'handle_rename_before', array());
62        $controller->register_hook('PLUGIN_MOVE_PAGE_RENAME', 'AFTER', $this, 'handle_rename_after', array());
63
64        /**
65         * To rewrite the link
66         */
67        $controller->register_hook('PLUGIN_MOVE_HANDLERS_REGISTER', 'BEFORE', $this, 'handle_link', array());
68
69
70        /**
71         * Check for the presence of a lock file
72         */
73        $controller->register_hook('PARSER_WIKITEXT_PREPROCESS', 'BEFORE', $this, 'check_lock_file_age', array());
74
75
76    }
77
78    /**
79     * @param Doku_Event $event
80     * @param $params
81     *
82     * When a lock file is present,
83     * the move plugin will purge the data in {@link action_plugin_move_rewrite::handle_cache()}
84     * making the rendering fucking slow
85     * We check that the lock file is not
86     */
87    function check_lock_file_age(Doku_Event $event, $params)
88    {
89        self::checkAndSendAMessageIfLockFilePresent();
90
91    }
92
93    /**
94     * Handle the path modification of a page
95     * @param Doku_Event $event - https://www.dokuwiki.org/plugin:move#for_plugin_authors
96     * @param $params
97     *
98     */
99    function handle_rename_before(Doku_Event $event, $params)
100    {
101        /**
102         * Check that the lock file is not older
103         * Lock file bigger than 5 minutes
104         * Is not really possible
105         */
106        $result = self::checkAndSendAMessageIfLockFilePresent();
107        if ($result === true) {
108            $event->preventDefault();
109            LogUtility::msg("The move lock file is present, the move was canceled.");
110        }
111
112    }
113
114    /**
115     * Handle the path modification of a page after
116     *
117     * The metadata file should also have been moved
118     *
119     * @param Doku_Event $event - https://www.dokuwiki.org/plugin:move#for_plugin_authors
120     * @param $params
121     *
122     */
123    function handle_rename_after(Doku_Event $event, $params)
124    {
125        /**
126         *
127         * $event->data
128         * src_id ⇒ string – the original ID of the page
129         * dst_id ⇒ string – the new ID of the page
130         */
131        $sourceId = $event->data["src_id"];
132        $targetId = $event->data["dst_id"];
133        try {
134
135            /**
136             * Update the dokuwiki id and path
137             */
138            $databasePage = DatabasePageRow::createFromDokuWikiId($sourceId);
139            if (!$databasePage->exists()) {
140                return;
141            }
142            $databasePage->updatePathAndDokuwikiId($targetId);
143
144            /**
145             * Check page id
146             */
147            $targetPage = Page::createPageFromId($targetId);
148            $targetPageId = PageId::createForPage($targetPage);
149            $targetPageIdValue = $targetPageId->getValueFromStore();
150            $databasePageIdValue = $databasePage->getPageId();
151
152            if ($databasePageIdValue !== $targetPageIdValue) {
153                // this should never happened in test/dev
154                $targetPageId->setValueForce($targetPageIdValue);
155            }
156
157            /**
158             * Add the alias
159             */
160            Aliases::createForPage($targetPage)
161                ->addAlias($sourceId)
162                ->setWriteStore(MetadataDokuWikiStore::class)
163                ->sendToWriteStore()
164                ->persist()
165                ->setReadStore(MetadataDbStore::class)
166                ->sendToWriteStore()
167                ->persist();
168
169
170        } catch (Exception $exception) {
171            // We catch the errors if any to not stop the move
172            // There is no transaction feature (it happens or not)
173            $message = "An error occurred during the move replication to the database. Error message was: " . $exception->getMessage();
174            if (PluginUtility::isDevOrTest()) {
175                throw new RuntimeException($exception);
176            } else {
177                LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::CANONICAL);
178            }
179        }
180
181    }
182
183
184    /**
185     * Handle the move of a page
186     * @param Doku_Event $event
187     * @param $params
188     */
189    function handle_link(Doku_Event $event, $params)
190    {
191        /**
192         * The handlers is the name of the component (ie refers to the {@link syntax_plugin_combo_link} handler)
193         * and 'rewrite_combo' to the below method
194         */
195        $event->data['handlers'][syntax_plugin_combo_link::COMPONENT] = array($this, 'rewrite_combo');
196    }
197
198    /**
199     *
200     * @param $match
201     * @param $state
202     * @param $pos
203     * @param $plugin
204     * @param helper_plugin_move_handler $handler
205     */
206    public function rewrite_combo($match, $state, $pos, $plugin, helper_plugin_move_handler $handler)
207    {
208        /**
209         * The original move method
210         * is {@link helper_plugin_move_handler::internallink()}
211         *
212         */
213        if ($state == DOKU_LEXER_ENTER) {
214            $ref = LinkUtility::parse($match)[LinkUtility::ATTRIBUTE_REF];
215            $link = new LinkUtility($ref);
216            if ($link->getType() == LinkUtility::TYPE_INTERNAL) {
217
218                $handler->internallink($match, $state, $pos);
219                $suffix = "]]";
220                if (substr($handler->calls, -strlen($suffix)) == $suffix) {
221                    $handler->calls = substr($handler->calls, 0, strlen($handler->calls) - strlen($suffix));
222                }
223
224            } else {
225
226                // Other type of links
227                $handler->calls .= $match;
228
229            }
230        } else {
231
232            // Description and ending
233            $handler->calls .= $match;
234
235        }
236    }
237
238
239}
240