1<?php
2
3
4use ComboStrap\ExceptionNotFound;
5use ComboStrap\ExceptionRuntimeInternal;
6use ComboStrap\ExecutionContext;
7use ComboStrap\LogUtility;
8use ComboStrap\MarkupPath;
9use ComboStrap\Meta\Api\MetadataSystem;
10use ComboStrap\Meta\Field\PageH1;
11use ComboStrap\Meta\Field\PageImages;
12use ComboStrap\Meta\Store\MetadataDokuWikiStore;
13use ComboStrap\MetadataDokuWikiArrayStore;
14use ComboStrap\MetadataFrontmatterStore;
15use ComboStrap\MetadataMutation;
16use ComboStrap\PluginUtility;
17use ComboStrap\References;
18
19/**
20 *
21 * Handle meta rendering processing
22 * * notifiy of changes
23 * * and other
24 *
25 *
26 * The changes notification takes place at the document level
27 * because we want to notify modication on array level (such as references, images)
28 * and not only on scalar.
29 */
30class action_plugin_combo_metaprocessing extends DokuWiki_Action_Plugin
31{
32
33
34    private array $beforeMetaArray;
35
36    public function register(Doku_Event_Handler $controller)
37    {
38        /**
39         * https://www.dokuwiki.org/devel:event:parser_metadata_render
40         */
41        $controller->register_hook('PARSER_METADATA_RENDER', 'BEFORE', $this, 'metadataProcessingBefore', array());
42        $controller->register_hook('PARSER_METADATA_RENDER', 'AFTER', $this, 'metadataProcessingAfter', array());
43
44
45    }
46
47
48    function metadataProcessingBefore($event)
49    {
50
51        /**
52         * Capture the before state
53         */
54        if (isset($this->beforeMetaArray)) {
55            throw new ExceptionRuntimeInternal("The before variable should be unset in the after method");
56        }
57        $this->beforeMetaArray = $event->data;
58    }
59
60    function metadataProcessingAfter($event)
61    {
62
63        $afterMetaArray = &$event->data;
64        $beforeMetaArray = $this->beforeMetaArray;
65        unset($this->beforeMetaArray);
66
67        $afterId = $afterMetaArray["page"];
68        $beforeId = $beforeMetaArray["page"];
69        if ($afterId !== $beforeId) {
70            LogUtility::internalError("The before ($beforeId) and after id ($afterId) are not the same", get_class($this));
71            return;
72        }
73
74        /**
75         * To avoid
76         * Console Info: slot_footer.xhtml: Cache (1681473480)
77         * is older than dependent C:\Users\GERARD~1\AppData\Local\Temp\dwtests-1681473476.2836\data\meta\cache_manager_slot_test.meta (1681473480), cache is not usable
78         * See {@link \ComboStrap\Test\TestUtility::WaitToCreateCacheFile1SecLater()}
79         */
80        if (PluginUtility::isDevOrTest()) {
81            sleep(1);
82        }
83
84        $page = MarkupPath::createMarkupFromId($afterId);
85
86        $primaryMetas = action_plugin_combo_pageprimarymetamutation::PRIMARY_METAS;
87        $referencesAttributes = [References::getPersistentName()];
88        $qualityMetadata = action_plugin_combo_qualitymutation::getQualityMetas();
89        $attributes = array_merge($primaryMetas, $referencesAttributes, $qualityMetadata);
90
91        $beforeStore = MetadataDokuWikiArrayStore::getOrCreateFromResource($page, $beforeMetaArray);
92        $afterStore = MetadataDokuWikiArrayStore::getOrCreateFromResource($page, $afterMetaArray);
93        /**
94         * The data should be formatted as if it was for the frontmatter
95         * TODO: make it a default for the mutation system ??
96         */
97        $targetStoreFormat = MetadataFrontmatterStore::class;
98        foreach ($attributes as $attribute) {
99
100            try {
101                $beforeMeta = MetadataSystem::getForName($attribute)
102                    ->setReadStore($beforeStore)
103                    ->setWriteStore($targetStoreFormat)
104                    ->setResource($page);
105                $afterMeta = MetadataSystem::getForName($attribute)
106                    ->setReadStore($afterStore)
107                    ->setWriteStore($targetStoreFormat)
108                    ->setResource($page);
109            } catch (ExceptionNotFound $e) {
110                LogUtility::internalError("The metadata was not found for the attribute ($attribute)");
111                continue;
112            }
113
114            try {
115                $beforeMeta->getValue();
116                $valueBefore = $beforeMeta->toStoreValue();
117            } catch (Exception $e) {
118                // first value
119                $valueBefore = null;
120            }
121
122            $valueAfter = $afterMeta->toStoreValue();
123            MetadataMutation::notifyMetadataMutation($attribute, $valueBefore, $valueAfter, $page);
124
125        }
126
127
128        /**
129         * We got a conflict Dokuwiki stores a `title` meta in the current
130         * Because we may delete the first heading, the stored title is the second
131         * heading, we update it
132         * See first line of {@link \Doku_Renderer_metadata::header()}
133         */
134        $isWikiDisabled = ExecutionContext::getActualOrCreateFromEnv()
135            ->getConfig()
136            ->isHeadingWikiComponentDisabled();
137        if ($isWikiDisabled) {
138            $event->data[MetadataDokuWikiStore::CURRENT_METADATA]['title'] = $event->data[MetadataDokuWikiStore::CURRENT_METADATA][PageH1::H1_PARSED];
139        }
140
141        /**
142         * Trick, don't know if this is always true
143         */
144        PageImages::createForPage($page)->modifyMetaDokuWikiArray($event->data);
145
146    }
147
148}
149