xref: /dokuwiki/inc/Action/Search.php (revision 8788dbbd585b42284320d64cc932f3c875eab6b2)
164ab5140SAndreas Gohr<?php
264ab5140SAndreas Gohr
364ab5140SAndreas Gohrnamespace dokuwiki\Action;
464ab5140SAndreas Gohr
564ab5140SAndreas Gohruse dokuwiki\Action\Exception\ActionAbort;
60cba610bSSatoshi Saharause dokuwiki\Search\FulltextSearch;
70cba610bSSatoshi Saharause dokuwiki\Search\MetadataSearch;
80b1bbbbbSAndreas Gohruse dokuwiki\Search\Query\QueryParser;
964ab5140SAndreas Gohr
10ab583a1bSAndreas Gohr/**
11ab583a1bSAndreas Gohr * Class Search
12ab583a1bSAndreas Gohr *
13ab583a1bSAndreas Gohr * Search for pages and content
14ab583a1bSAndreas Gohr *
15ab583a1bSAndreas Gohr * @package dokuwiki\Action
16ab583a1bSAndreas Gohr */
178c7c53b0SAndreas Gohrclass Search extends AbstractAction
188c7c53b0SAndreas Gohr{
196723156fSAndreas Gohr    protected $pageLookupResults = [];
206723156fSAndreas Gohr    protected $fullTextResults = [];
216723156fSAndreas Gohr    protected $highlight = [];
226639a152SMichael Große
2364ab5140SAndreas Gohr    /** @inheritdoc */
24d868eb89SAndreas Gohr    public function minimumPermission()
25d868eb89SAndreas Gohr    {
2664ab5140SAndreas Gohr        return AUTH_NONE;
2764ab5140SAndreas Gohr    }
2864ab5140SAndreas Gohr
2964ab5140SAndreas Gohr    /**
3064ab5140SAndreas Gohr     * we only search if a search word was given
3164ab5140SAndreas Gohr     *
3264ab5140SAndreas Gohr     * @inheritdoc
3364ab5140SAndreas Gohr     */
34d868eb89SAndreas Gohr    public function checkPreconditions()
35d868eb89SAndreas Gohr    {
36b2c9cd19SAndreas Gohr        parent::checkPreconditions();
3764ab5140SAndreas Gohr    }
3864ab5140SAndreas Gohr
39d09b5b64SMichael Große    public function preProcess()
40d09b5b64SMichael Große    {
41d22b78c8SMichael Große        global $QUERY, $ID, $conf, $INPUT;
42d22b78c8SMichael Große        $s = cleanID($QUERY);
43d22b78c8SMichael Große
443286c65dSMichael Große        if ($ID !== $conf['start'] && !$INPUT->has('q')) {
45d22b78c8SMichael Große            parse_str($INPUT->server->str('QUERY_STRING'), $urlParts);
46d22b78c8SMichael Große            $urlParts['q'] = $urlParts['id'];
47918638dcSSchplurtz le Déboulonné            unset($urlParts['id']);
48cc21cb50SAndreas Gohr            $url = wl($ID, $urlParts, true, '&');
49d22b78c8SMichael Große            send_redirect($url);
50d22b78c8SMichael Große        }
51d22b78c8SMichael Große
52d22b78c8SMichael Große        if ($s === '') throw new ActionAbort();
53d09b5b64SMichael Große        $this->adjustGlobalQuery();
54d09b5b64SMichael Große    }
55d09b5b64SMichael Große
5664ab5140SAndreas Gohr    /** @inheritdoc */
57d09b5b64SMichael Große    public function tplContent()
58d09b5b64SMichael Große    {
596639a152SMichael Große        $this->execute();
606639a152SMichael Große
616639a152SMichael Große        $search = new \dokuwiki\Ui\Search($this->pageLookupResults, $this->fullTextResults, $this->highlight);
6221fcef82SMichael Große        $search->show();
6364ab5140SAndreas Gohr    }
64d09b5b64SMichael Große
656639a152SMichael Große
666639a152SMichael Große    /**
676639a152SMichael Große     * run the search
686639a152SMichael Große     */
696639a152SMichael Große    protected function execute()
706639a152SMichael Große    {
716639a152SMichael Große        global $INPUT, $QUERY;
72422bbbc6SMichael Große        $after = $INPUT->str('min');
73422bbbc6SMichael Große        $before = $INPUT->str('max');
74*8788dbbdSsplitbrain        $this->pageLookupResults = (new MetadataSearch())->pageLookup(
75*8788dbbdSsplitbrain            $QUERY,
76*8788dbbdSsplitbrain            true,
77*8788dbbdSsplitbrain            useHeading('navigation'),
78*8788dbbdSsplitbrain            $after,
79*8788dbbdSsplitbrain            $before
809329b002SSatoshi Sahara        );
819313ce6dSAndreas Gohr        $highlight = [];
82*8788dbbdSsplitbrain        $this->fullTextResults = (new FulltextSearch())->pageSearch(
83*8788dbbdSsplitbrain            $QUERY,
84*8788dbbdSsplitbrain            $highlight,
85*8788dbbdSsplitbrain            $INPUT->str('srt'),
86*8788dbbdSsplitbrain            $after,
87*8788dbbdSsplitbrain            $before
889329b002SSatoshi Sahara        );
896639a152SMichael Große        $this->highlight = $highlight;
906639a152SMichael Große    }
916639a152SMichael Große
92d09b5b64SMichael Große    /**
9313ce475dSAndreas Gohr     * Adjust the global query accordingly to the config search_nslimit and search_fragment
94d09b5b64SMichael Große     *
95d09b5b64SMichael Große     * This will only do something if the search didn't originate from the form on the searchpage itself
96d09b5b64SMichael Große     */
97d09b5b64SMichael Große    protected function adjustGlobalQuery()
98d09b5b64SMichael Große    {
99340f849aSMichael Große        global $conf, $INPUT, $QUERY, $ID;
100d09b5b64SMichael Große
1011265b193SMichael Große        if ($INPUT->bool('sf')) {
102d09b5b64SMichael Große            return;
103d09b5b64SMichael Große        }
104d09b5b64SMichael Große
105*8788dbbdSsplitbrain        $parsedQuery = (new QueryParser())->convert($QUERY);
106d09b5b64SMichael Große
107d09b5b64SMichael Große        if (empty($parsedQuery['ns']) && empty($parsedQuery['notns'])) {
10813ce475dSAndreas Gohr            if ($conf['search_nslimit'] > 0) {
109340f849aSMichael Große                if (getNS($ID) !== false) {
110340f849aSMichael Große                    $nsParts = explode(':', getNS($ID));
11113ce475dSAndreas Gohr                    $ns = implode(':', array_slice($nsParts, 0, $conf['search_nslimit']));
112d09b5b64SMichael Große                    $QUERY .= " @$ns";
113d09b5b64SMichael Große                }
114d09b5b64SMichael Große            }
115d09b5b64SMichael Große        }
116d09b5b64SMichael Große
11713ce475dSAndreas Gohr        if ($conf['search_fragment'] !== 'exact') {
118d09b5b64SMichael Große            if (empty(array_diff($parsedQuery['words'], $parsedQuery['and']))) {
119093fe67eSAndreas Gohr                if (!str_contains($QUERY, '*')) {
120d09b5b64SMichael Große                    $queryParts = explode(' ', $QUERY);
121d09b5b64SMichael Große                    $queryParts = array_map(function ($part) {
122093fe67eSAndreas Gohr                        if (str_starts_with($part, '@')) {
123d09b5b64SMichael Große                            return $part;
124d09b5b64SMichael Große                        }
125093fe67eSAndreas Gohr                        if (str_starts_with($part, 'ns:')) {
126d09b5b64SMichael Große                            return $part;
127d09b5b64SMichael Große                        }
128093fe67eSAndreas Gohr                        if (str_starts_with($part, '^')) {
129d09b5b64SMichael Große                            return $part;
130d09b5b64SMichael Große                        }
131093fe67eSAndreas Gohr                        if (str_starts_with($part, '-ns:')) {
132d09b5b64SMichael Große                            return $part;
133d09b5b64SMichael Große                        }
134d09b5b64SMichael Große
135d09b5b64SMichael Große                        global $conf;
136d09b5b64SMichael Große
13713ce475dSAndreas Gohr                        if ($conf['search_fragment'] === 'starts_with') {
138d09b5b64SMichael Große                            return $part . '*';
139d09b5b64SMichael Große                        }
14013ce475dSAndreas Gohr                        if ($conf['search_fragment'] === 'ends_with') {
141d09b5b64SMichael Große                            return '*' . $part;
142d09b5b64SMichael Große                        }
143d09b5b64SMichael Große
144d09b5b64SMichael Große                        return '*' . $part . '*';
145d09b5b64SMichael Große                    }, $queryParts);
146d09b5b64SMichael Große                    $QUERY = implode(' ', $queryParts);
147d09b5b64SMichael Große                }
148d09b5b64SMichael Große            }
149d09b5b64SMichael Große        }
150d09b5b64SMichael Große    }
15164ab5140SAndreas Gohr}
152