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            'prefix' => '#',
75            'id' => 'plugin__tagging-tags',
76            'fieldPath' => 'tagging',
77            'limit' => '100',
78        ];
79    }
80
81    /**
82     * Remove tags from query string and put them into $INPUT
83     * to be used as filter by Elasticsearch.
84     * Also return new #tag values to be appended to the query.
85     *
86     * @param Doku_Event $event
87     */
88    public function setupTagSearchElastic(Doku_Event $event)
89    {
90        global $QUERY;
91        global $INPUT;
92
93        /** @var helper_plugin_tagging $hlp */
94        $hlp = plugin_load('helper', 'tagging');
95
96        $taggingFilter = $INPUT->arr('tagging');
97
98        // get (hash)tags from query
99        preg_match_all('/(?:#)(\w+)/u', $QUERY, $matches);
100        if (isset($matches[1])) {
101            $matches[1] = array_map([$hlp, 'cleanTag'], $matches[1]);
102            $INPUT->set('tagging', array_merge($matches[1], $taggingFilter));
103        }
104        \action_plugin_tagging_search::removeTagsFromQuery($QUERY);
105
106        // return tagging filter as hashtags to be appended to the original query (without doubles)
107        if ($taggingFilter) {
108            $additions = array_map(function ($tag) use ($matches) {
109                if (!isset($matches[1]) || !in_array($tag, $matches[1])) {
110                    return "#$tag";
111                }
112                return null;
113            }, $taggingFilter);
114            $event->data += array_filter($additions);
115        }
116    }
117
118    /**
119     * Add tagging to the list of search fields
120     *
121     * @param Doku_Event $event
122     */
123    public function elasticSearchFields(Doku_Event $event)
124    {
125        array_push($event->data, 'tagging');
126    }
127}
128