xref: /dokuwiki/inc/Action/Search.php (revision 9313ce6d4644bdf080e6c01951187fcbf6a3682f)
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');
74cc3a3cdeSSatoshi Sahara        $this->pageLookupResults = (new MetadataSearch)->pageLookup(
759329b002SSatoshi Sahara                $QUERY, true, useHeading('navigation'), $after, $before
769329b002SSatoshi Sahara        );
77*9313ce6dSAndreas Gohr        $highlight = [];
78cc3a3cdeSSatoshi Sahara        $this->fullTextResults = (new FulltextSearch)->pageSearch(
799329b002SSatoshi Sahara                $QUERY, $highlight, $INPUT->str('srt'), $after, $before
809329b002SSatoshi Sahara        );
816639a152SMichael Große        $this->highlight = $highlight;
826639a152SMichael Große    }
836639a152SMichael Große
84d09b5b64SMichael Große    /**
8513ce475dSAndreas Gohr     * Adjust the global query accordingly to the config search_nslimit and search_fragment
86d09b5b64SMichael Große     *
87d09b5b64SMichael Große     * This will only do something if the search didn't originate from the form on the searchpage itself
88d09b5b64SMichael Große     */
89d09b5b64SMichael Große    protected function adjustGlobalQuery()
90d09b5b64SMichael Große    {
91340f849aSMichael Große        global $conf, $INPUT, $QUERY, $ID;
92d09b5b64SMichael Große
931265b193SMichael Große        if ($INPUT->bool('sf')) {
94d09b5b64SMichael Große            return;
95d09b5b64SMichael Große        }
96d09b5b64SMichael Große
979329b002SSatoshi Sahara        $parsedQuery = (new QueryParser)->convert($QUERY);
98d09b5b64SMichael Große
99d09b5b64SMichael Große        if (empty($parsedQuery['ns']) && empty($parsedQuery['notns'])) {
10013ce475dSAndreas Gohr            if ($conf['search_nslimit'] > 0) {
101340f849aSMichael Große                if (getNS($ID) !== false) {
102340f849aSMichael Große                    $nsParts = explode(':', getNS($ID));
10313ce475dSAndreas Gohr                    $ns = implode(':', array_slice($nsParts, 0, $conf['search_nslimit']));
104d09b5b64SMichael Große                    $QUERY .= " @$ns";
105d09b5b64SMichael Große                }
106d09b5b64SMichael Große            }
107d09b5b64SMichael Große        }
108d09b5b64SMichael Große
10913ce475dSAndreas Gohr        if ($conf['search_fragment'] !== 'exact') {
110d09b5b64SMichael Große            if (empty(array_diff($parsedQuery['words'], $parsedQuery['and']))) {
111093fe67eSAndreas Gohr                if (!str_contains($QUERY, '*')) {
112d09b5b64SMichael Große                    $queryParts = explode(' ', $QUERY);
113d09b5b64SMichael Große                    $queryParts = array_map(function ($part) {
114093fe67eSAndreas Gohr                        if (str_starts_with($part, '@')) {
115d09b5b64SMichael Große                            return $part;
116d09b5b64SMichael Große                        }
117093fe67eSAndreas Gohr                        if (str_starts_with($part, 'ns:')) {
118d09b5b64SMichael Große                            return $part;
119d09b5b64SMichael Große                        }
120093fe67eSAndreas Gohr                        if (str_starts_with($part, '^')) {
121d09b5b64SMichael Große                            return $part;
122d09b5b64SMichael Große                        }
123093fe67eSAndreas Gohr                        if (str_starts_with($part, '-ns:')) {
124d09b5b64SMichael Große                            return $part;
125d09b5b64SMichael Große                        }
126d09b5b64SMichael Große
127d09b5b64SMichael Große                        global $conf;
128d09b5b64SMichael Große
12913ce475dSAndreas Gohr                        if ($conf['search_fragment'] === 'starts_with') {
130d09b5b64SMichael Große                            return $part . '*';
131d09b5b64SMichael Große                        }
13213ce475dSAndreas Gohr                        if ($conf['search_fragment'] === 'ends_with') {
133d09b5b64SMichael Große                            return '*' . $part;
134d09b5b64SMichael Große                        }
135d09b5b64SMichael Große
136d09b5b64SMichael Große                        return '*' . $part . '*';
137d09b5b64SMichael Große                    }, $queryParts);
138d09b5b64SMichael Große                    $QUERY = implode(' ', $queryParts);
139d09b5b64SMichael Große                }
140d09b5b64SMichael Große            }
141d09b5b64SMichael Große        }
142d09b5b64SMichael Große    }
14364ab5140SAndreas Gohr}
144