1<?php
2
3use ComboStrap\ExceptionBadArgument;
4use ComboStrap\ExceptionCompile;
5use ComboStrap\ExceptionNotFound;
6use ComboStrap\ExceptionRuntime;
7use ComboStrap\ExecutionContext;
8use ComboStrap\LogUtility;
9use ComboStrap\MarkupPath;
10use ComboStrap\Meta\Api\MetadataImage;
11use ComboStrap\Meta\Api\MetadataSystem;
12use ComboStrap\Meta\Field\PageImages;
13use ComboStrap\Meta\Store\MetadataDokuWikiStore;
14use ComboStrap\MetadataFrontmatterStore;
15use ComboStrap\PageImageUsage;
16use ComboStrap\PluginUtility;
17use ComboStrap\WikiPath;
18
19require_once(__DIR__ . '/../vendor/autoload.php');
20
21/**
22 * Handle the move of a image
23 */
24class action_plugin_combo_imgmove extends DokuWiki_Action_Plugin
25{
26    const CANONICAL = "imgmove";
27
28    /**
29     * As explained https://www.dokuwiki.org/plugin:move
30     * @param Doku_Event_Handler $controller
31     */
32    function register(Doku_Event_Handler $controller)
33    {
34        $controller->register_hook('PLUGIN_MOVE_HANDLERS_REGISTER', 'BEFORE', $this, 'handle_move', array());
35
36
37        $controller->register_hook('PLUGIN_MOVE_MEDIA_RENAME', 'AFTER', $this, 'fileSystemStoreUpdate', array());
38    }
39
40    /**
41     * Update the metadatas
42     * @param Doku_Event $event
43     * @param $params
44     */
45    function fileSystemStoreUpdate(Doku_Event $event, $params)
46    {
47
48
49        $affectedPagesId = $event->data["affected_pages"];
50        $sourceImageId = $event->data["src_id"];
51        $targetImageId = $event->data["dst_id"];
52
53        /**
54         * Advertise the move
55         */
56        ExecutionContext::getActualOrCreateFromEnv()
57            ->setRuntimeObject(action_plugin_combo_linkmove::FILE_MOVE_OPERATION, $sourceImageId);
58        try {
59            foreach ($affectedPagesId as $affectedPageId) {
60                $affectedPage = MarkupPath::createMarkupFromId($affectedPageId)
61                    ->setReadStore(MetadataDokuWikiStore::class);
62
63                foreach (MetadataImage::PERSISTENT_IMAGE_NAMES as $persistentImage) {
64                    try {
65                        $metadata = MetadataSystem::getForName($persistentImage)
66                            ->setResource($affectedPage)
67                            ->setReadStore(MetadataDokuWikiStore::class);
68                    } catch (ExceptionNotFound $e) {
69                        LogUtility::internalError("Hardcoded should exists");
70                        continue;
71                    }
72                    try {
73                        $value = $metadata->getValue();
74                    } catch (ExceptionNotFound $e) {
75                        // no value
76                        continue;
77                    }
78                    if ($value === $sourceImageId) {
79                        try {
80                            $metadata
81                                ->setValue($targetImageId)
82                                ->persist();
83                        } catch (ExceptionBadArgument $e) {
84                            LogUtility::error("The target path image ($targetImageId) is not a path", self::CANONICAL, $e);
85                        }
86                    }
87                }
88
89
90                /**
91                 * Deprecated but yeah
92                 */
93                $pageImages = PageImages::createForPage($affectedPage);
94                $sourceImagePath = ":$sourceImageId";
95                $row = $pageImages->getRow($sourceImagePath);
96                if ($row === null) {
97                    // This is a move of an image in the markup
98                    continue;
99                }
100                $souceImageWikiPath = WikiPath::createMediaPathFromId($sourceImagePath);
101                $pageImages->remove($souceImageWikiPath);
102                try {
103                    $imageUsage = $row[PageImageUsage::getPersistentName()] ?? null;
104                    $imageUsageValue = null;
105                    if ($imageUsage !== null) {
106                        $imageUsageValue = $imageUsage->getValue();
107                    }
108                    $pageImages
109                        ->addImage($targetImageId, $imageUsageValue)
110                        ->persist();
111                } catch (ExceptionCompile $e) {
112                    LogUtility::log2file($e->getMessage(), LogUtility::LVL_MSG_ERROR, $e->getCanonical(), $e);
113                }
114
115            }
116        } finally {
117            /**
118             * Stop advertising the move
119             */
120            ExecutionContext::getActualOrCreateFromEnv()
121                ->closeAndRemoveRuntimeVariableIfExists(action_plugin_combo_linkmove::FILE_MOVE_OPERATION);
122        }
123
124    }
125
126    /**
127     * Handle the move of a image
128     * @param Doku_Event $event
129     * @param $params
130     */
131    function handle_move(Doku_Event $event, $params)
132    {
133        /**
134         * The handlers is the name of the component (ie refers to the {@link syntax_plugin_combo_media} handler)
135         * and 'move_combo_img' to the below method
136         */
137        $event->data['handlers'][syntax_plugin_combo_media::COMPONENT] = array($this, 'move_combo_img');
138        $event->data['handlers'][syntax_plugin_combo_frontmatter::COMPONENT] = array($this, 'move_combo_frontmatter_img');
139
140    }
141
142    /**
143     *
144     * @param $match
145     * @param $state
146     * @param $pos
147     * @param $plugin
148     * @param helper_plugin_move_handler $handler
149     */
150    public function move_combo_img($match, $state, $pos, $plugin, helper_plugin_move_handler $handler)
151    {
152        /**
153         * The original move method
154         * is {@link helper_plugin_move_handler::media()}
155         * Rewrite the media links match
156         * from {@link syntax_plugin_combo_media}
157         */
158        $handler->media($match, $state, $pos);
159
160    }
161
162    /**
163     *
164     * @param $match
165     * @param $state
166     * @param $pos
167     * @param $plugin
168     * @param helper_plugin_move_handler $handler
169     * @return string
170     */
171    public function move_combo_frontmatter_img($match, $state, $pos, $plugin, helper_plugin_move_handler $handler)
172    {
173        /**
174         * The original move method
175         * is {@link helper_plugin_move_handler::media()}
176         */
177        $page = MarkupPath::createMarkupFromId("move-fake-id");
178        try {
179            $metadataFrontmatterStore = MetadataFrontmatterStore::createFromFrontmatterString($page, $match);
180        } catch (ExceptionCompile $e) {
181            LogUtility::msg("The frontmatter could not be loaded. " . $e->getMessage(), LogUtility::LVL_MSG_ERROR, $e->getCanonical());
182            return $match;
183        }
184        $data = $metadataFrontmatterStore->getData();
185
186        /**
187         * Advertise the move
188         */
189        $moveOpeation = true;
190        ExecutionContext::getActualOrCreateFromEnv()
191            ->setRuntimeObject(action_plugin_combo_linkmove::FILE_MOVE_OPERATION, $moveOpeation);
192        try {
193            foreach ($data as $key => $value) {
194
195                try {
196                    $metadata = MetadataSystem::getForName($key)
197                        ->setResource($page)
198                        ->setReadStore($metadataFrontmatterStore)
199                        ->setWriteStore($metadataFrontmatterStore);
200                } catch (ExceptionNotFound $e) {
201                    continue;
202                }
203
204                /**
205                 * Old deprecated
206                 */
207                if ($metadata instanceof PageImages) {
208                    $pageImagesObject = $metadata;
209                    $images = $metadata->getValueAsPageImages();
210                    if (empty($images)) {
211                        return $match;
212                    }
213                    try {
214
215                        foreach ($images as $image) {
216                            $path = $image->getImagePath();
217                            $imageId = $path->toAbsolutePath()->toAbsoluteId();
218                            $before = $imageId;
219                            $this->moveImage($imageId, $handler);
220                            if ($before !== $imageId) {
221                                $pageImagesObject->remove($path);
222                                $pageImagesObject->addImage($imageId, $image->getUsages());
223                            }
224                        }
225
226                        $pageImagesObject->sendToWriteStore();
227
228                    } catch (ExceptionCompile $e) {
229                        // Could not resolve the image, image does not exist, ... return the data without modification
230                        if (PluginUtility::isDevOrTest()) {
231                            throw new ExceptionRuntime($e->getMessage(), $e->getCanonical(), 0, $e);
232                        } else {
233                            LogUtility::log2file($e->getMessage(), LogUtility::LVL_MSG_ERROR, $e->getCanonical());
234                        }
235                        continue;
236                    }
237                }
238                if (!($metadata instanceof MetadataImage)) {
239                    continue;
240                }
241                try {
242                    $imageId = $metadata->getValue()->toAbsoluteId();
243                } catch (ExceptionNotFound $e) {
244                    continue;
245                }
246                $before = $imageId;
247                try {
248                    $this->moveImage($imageId, $handler);
249                    if ($before !== $imageId) {
250                        $metadata->setValue($imageId)->persist();
251                    }
252                } catch (\Exception $e) {
253                    if (PluginUtility::isDevOrTest()) {
254                        throw new ExceptionRuntime($e->getMessage(), self::CANONICAL, 0, $e);
255                    } else {
256                        LogUtility::log2file($e->getMessage(), LogUtility::LVL_MSG_ERROR, self::CANONICAL, $e);
257                    }
258                    continue;
259                }
260            }
261        } finally {
262            /**
263             * Close the move
264             */
265            ExecutionContext::getActualOrCreateFromEnv()
266                ->closeAndRemoveRuntimeVariableIfExists(action_plugin_combo_linkmove::FILE_MOVE_OPERATION);
267        }
268
269
270        /**
271         * All good,
272         * We don't modify the file system metadata for the page
273         * because the handler does not give it unfortunately
274         */
275        return $metadataFrontmatterStore->toFrontmatterString();
276
277    }
278
279    /**
280     * Move a single image and update the JSon
281     * @param $relativeOrAbsoluteWikiId
282     * @param helper_plugin_move_handler $handler
283     * @throws ExceptionCompile on bad argument
284     */
285    private function moveImage(&$relativeOrAbsoluteWikiId, helper_plugin_move_handler $handler)
286    {
287        try {
288            $newId = $handler->resolveMoves($relativeOrAbsoluteWikiId, "media");
289            $relativeOrAbsoluteWikiId = WikiPath::IdToAbsolutePath($newId);
290        } catch (Exception $e) {
291            throw new ExceptionCompile("A move error has occurred while trying to move the image ($relativeOrAbsoluteWikiId). The target resolution function send the following error message: " . $e->getMessage(), self::CANONICAL);
292        }
293    }
294
295
296}
297