1<?php
2
3/**
4 * Class action_plugin_tagging_elasticsearch
5 */
6class action_plugin_tagging_elasticsearch extends DokuWiki_Action_Plugin
7{
8
9    public function register(Doku_Event_Handler $controller)
10    {
11        $controller->register_hook(
12            'PLUGIN_ELASTICSEARCH_CREATEMAPPING', 'BEFORE', $this,
13            'elasticMapping'
14        );
15
16        $controller->register_hook(
17            'PLUGIN_ELASTICSEARCH_INDEXPAGE', 'BEFORE', $this,
18            'elasticIndexPage'
19        );
20
21        $controller->register_hook(
22            'PLUGIN_ELASTICSEARCH_FILTERS', 'BEFORE', $this,
23            'elasticSearchFilter'
24        );
25
26        $controller->register_hook(
27            'PLUGIN_ELASTICSEARCH_SEARCHFIELDS', 'BEFORE', $this,
28            'elasticSearchFields'
29        );
30
31        $controller->register_hook(
32            'PLUGIN_ELASTICSEARCH_QUERY', 'BEFORE', $this,
33            'setupTagSearchElastic'
34        );
35    }
36    /**
37     * Add our own field mapping to Elasticsearch
38     *
39     * @param Doku_Event $event
40     */
41    public function elasticMapping(Doku_Event $event)
42    {
43        $event->data[] = ['tagging' => ['type' => 'keyword']];
44    }
45
46    /**
47     * Add taggings to Elastic index
48     *
49     * @param Doku_Event $event
50     */
51    public function elasticIndexPage(Doku_Event $event)
52    {
53        $data = &$event->data;
54
55        /** @var helper_plugin_tagging $hlp */
56        $hlp = plugin_load('helper', 'tagging');
57        $tags = $hlp->findItems(['pid' => $data['uri']], 'tag');
58
59        $data['tagging'] = array_map(function ($tag) use ($hlp) {
60            return $hlp->cleanTag($tag);
61        }, array_keys($tags));
62    }
63
64    /**
65     * Add configuration for tagging filter in advanced search
66     * when using Elasticsearch plugin
67     *
68     * @param Doku_Event $event
69     */
70    public function elasticSearchFilter(Doku_Event $event)
71    {
72        $event->data['tagging'] = [
73            'label' => $this->getLang('search_filter_label'),
74            'id' => 'plugin__tagging-tags',
75            'fieldPath' => 'tagging',
76            'limit' => '100',
77        ];
78    }
79
80    /**
81     * Remove tags from query string and put them into $INPUT
82     * to be used as filter by Elasticsearch.
83     * Also return new #tag values to be appended to the query.
84     *
85     * @param Doku_Event $event
86     */
87    public function setupTagSearchElastic(Doku_Event $event)
88    {
89        global $QUERY;
90        global $INPUT;
91
92        /** @var helper_plugin_tagging $hlp */
93        $hlp = plugin_load('helper', 'tagging');
94
95        $taggingFilter = $INPUT->arr('tagging');
96
97        // get (hash)tags from query
98        preg_match_all('/(?:#)(\w+)/u', $QUERY, $matches);
99        if (isset($matches[1])) {
100            $matches[1] = array_map([$hlp, 'cleanTag'], $matches[1]);
101            $INPUT->set('tagging', array_merge($matches[1], $taggingFilter));
102        }
103        \action_plugin_tagging_search::removeTagsFromQuery($QUERY);
104
105        // return tagging filter as hashtags to be appended to the original query (without doubles)
106        if ($taggingFilter) {
107            $additions = array_map(function ($tag) use ($matches) {
108                if (!isset($matches[1]) || !in_array($tag, $matches[1])) {
109                    return "#$tag";
110                }
111                return null;
112            }, $taggingFilter);
113            $event->data += array_filter($additions);
114        }
115    }
116
117    /**
118     * Add tagging to the list of search fields
119     *
120     * @param Doku_Event $event
121     */
122    public function elasticSearchFields(Doku_Event $event)
123    {
124        array_push($event->data, 'tagging');
125    }
126}
127