1<?php
2
3require_once(__DIR__ . '/../vendor/autoload.php');
4
5use ComboStrap\CacheLog;
6use ComboStrap\Event;
7use ComboStrap\ExceptionCompile;
8use ComboStrap\ExceptionNotExists;
9use ComboStrap\LogUtility;
10use ComboStrap\MarkupCacheDependencies;
11use ComboStrap\MarkupPath;
12use ComboStrap\MetadataMutation;
13use ComboStrap\PagePath;
14use ComboStrap\Reference;
15use ComboStrap\References;
16
17
18/**
19 * Refresh the analytics when a backlink mutation occurs for a page
20 */
21class action_plugin_combo_backlinkmutation extends DokuWiki_Action_Plugin
22{
23
24
25    public const BACKLINK_MUTATION_EVENT_NAME = 'backlink_mutation';
26
27
28    public function register(Doku_Event_Handler $controller)
29    {
30
31
32        /**
33         * create the async event
34         */
35        $controller->register_hook(MetadataMutation::PAGE_METADATA_MUTATION_EVENT, 'AFTER', $this, 'create_backlink_mutation', array());
36
37        /**
38         * process the Async event
39         */
40        $controller->register_hook(self::BACKLINK_MUTATION_EVENT_NAME, 'AFTER', $this, 'handle_backlink_mutation');
41
42
43    }
44
45    /**
46     * @param Doku_Event $event
47     * @param $param
48     * @return void
49     */
50    public function handle_backlink_mutation(Doku_Event $event, $param)
51    {
52
53
54        $data = $event->data;
55        $pagePath = $data[PagePath::getPersistentName()] ?? null;
56        if ($pagePath === null) {
57            // https://github.com/ComboStrap/combo/issues/58
58            LogUtility::internalError("The page path should be present");
59            return;
60        }
61        $reference = MarkupPath::createPageFromAbsoluteId($pagePath);
62
63        if ($reference->isSlot()) {
64            return;
65        }
66
67        /**
68         * Delete and recompute analytics
69         */
70        try {
71            $analyticsDocument = $reference->fetchAnalyticsDocument();
72        } catch (ExceptionNotExists $e) {
73            return;
74        }
75        CacheLog::deleteCacheIfExistsAndLog(
76            $analyticsDocument,
77            self::BACKLINK_MUTATION_EVENT_NAME,
78            "Backlink mutation"
79        );
80
81        try {
82            /**
83             * This is only to recompute the {@link \ComboStrap\Meta\Field\BacklinkCount backlinks metric} and
84             * {@link \ComboStrap\LowQualityPage low quality page metrics}
85             * TODO: when the derived meta are in the meta array and not in the {@link renderer_plugin_combo_analytics document},
86             *   we could just compute them there and modify it with a plus 1
87             */
88            $reference->getDatabasePage()->replicateAnalytics();
89        } catch (ExceptionCompile $e) {
90            LogUtility::msg("Backlink Mutation: Error while trying to replicate the analytics. Error: {$e->getMessage()}");
91        }
92
93        /**
94         * Render the (footer slot) if it has a backlink dependency
95         */
96        MarkupCacheDependencies::reRenderSideSlotIfNeeded(
97            $pagePath,
98            MarkupCacheDependencies::BACKLINKS_DEPENDENCY,
99            self::BACKLINK_MUTATION_EVENT_NAME
100        );
101
102
103    }
104
105    /**
106     */
107    function create_backlink_mutation(Doku_Event $event, $params)
108    {
109
110
111        $data = $event->data;
112
113        /**
114         * If this is not a mutation on references we return.
115         */
116        if ($data[MetadataMutation::NAME_ATTRIBUTE] !== References::getPersistentName()) {
117            return;
118        };
119
120        $actualReferenceDatas = $data[MetadataMutation::NEW_VALUE_ATTRIBUTE];
121        $oldReferenceDatas = $data[MetadataMutation::OLD_VALUE_ATTRIBUTE];
122
123        /**
124         * Create an array of the actual reference with the key as path
125         */
126        $actualReferences = [];
127        if ($actualReferenceDatas !== null) {
128            foreach ($actualReferenceDatas as $actualReferenceData) {
129                $actualReferenceWikiPathString = $actualReferenceData[Reference::getPersistentName()];
130                $actualReferences[$actualReferenceWikiPathString] = $actualReferenceWikiPathString;
131            }
132        }
133
134        if ($oldReferenceDatas !== null) {
135            foreach ($oldReferenceDatas as $oldReferenceData) {
136
137                $oldReferenceWikiPathString = $oldReferenceData[Reference::getPersistentName()] ?? null;
138
139                if (isset($actualReferences[$oldReferenceWikiPathString])) {
140                    unset($actualReferences[$oldReferenceWikiPathString]);
141                    continue;
142                }
143
144                /**
145                 * Deleted reference
146                 */
147                Event::createEvent(
148                    action_plugin_combo_backlinkmutation::BACKLINK_MUTATION_EVENT_NAME,
149                    [
150                        PagePath::getPersistentName() => $oldReferenceWikiPathString
151                    ]
152                );
153
154            }
155        }
156
157        /**
158         * The new references
159         */
160        foreach ($actualReferences as $newReference) {
161            Event::createEvent(
162                action_plugin_combo_backlinkmutation::BACKLINK_MUTATION_EVENT_NAME,
163                [PagePath::getPersistentName() => $newReference]);
164        }
165
166
167    }
168
169
170}
171