Passed
Push — master ( 8e2b60...0d04df )
by Andreas
09:06
created

populate_toolbar()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 18
ccs 13
cts 13
cp 1
crap 4
rs 9.8666
1
<?php
2
/**
3
 * @package midcom.helper.search
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
use Symfony\Component\HttpFoundation\InputBag;
10
use Symfony\Component\HttpFoundation\Request;
11
12
/**
13
 * Search handler
14
 *
15
 * @package midcom.helper.search
16
 */
17
class midcom_helper_search_handler_search extends midcom_baseclasses_components_handler
18
{
19
    /**
20
     * Search form handler, nothing to do here.
21
     *
22
     * It uses the handler ID to distinguish between basic and advanced search forms.
23
     */
24 2
    public function _handler_searchform(Request $request, string $handler_id)
25
    {
26 2
        $this->prepare_formdata($handler_id, $request);
27 2
        $this->populate_toolbar($request);
28 2
        return $this->show('search_form');
29
    }
30
31 4
    private function prepare_formdata(string $handler_id, Request $request)
32
    {
33 4
        $this->_request_data['query'] = $this->fetch($request, 'query', '');
34 4
        if ($handler_id === 'advanced') {
35 2
            $this->_request_data['request_topic'] = trim($this->fetch($request, 'topic', ''));
36 2
            $this->_request_data['component'] = trim($this->fetch($request, 'component', ''));
37 2
            $this->_request_data['lastmodified'] = (int) trim($this->fetch($request, 'lastmodified', '0'));
38
39 2
            $this->_request_data['topics'] = ['' => $this->_l10n->get('search anywhere')];
40 2
            $this->_request_data['components'] = ['' => $this->_l10n->get('search all content types')];
41
42 2
            $nap = new midcom_helper_nav();
43 2
            $this->search_nodes($nap->get_node($nap->get_root_node()), $nap, '');
0 ignored issues
show
Bug introduced by
It seems like $nap->get_node($nap->get_root_node()) can also be of type null; however, parameter $node of midcom_helper_search_han..._search::search_nodes() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

43
            $this->search_nodes(/** @scrutinizer ignore-type */ $nap->get_node($nap->get_root_node()), $nap, '');
Loading history...
44
        }
45 4
        $this->_request_data['type'] = $handler_id;
46
    }
47
48 4
    private function fetch(Request $request, string $field, $default = null)
49
    {
50 4
        if ($request->request->has($field)) {
51
            return $request->request->get($field);
52
        }
53 4
        return $request->query->get($field, $default);
54
    }
55
56
    /**
57
     * Prepare the topic and component listings, this is a bit work intensive though,
58
     * we need to traverse everything.
59
     */
60 2
    private function search_nodes(array $node, midcom_helper_nav $nap, string $prefix)
61
    {
62 2
        if (   !array_key_exists($node[MIDCOM_NAV_COMPONENT], $this->_request_data['components'])
63 2
            && $node[MIDCOM_NAV_COMPONENT] != 'midcom.helper.search') {
64
            $l10n = $this->_i18n->get_l10n($node[MIDCOM_NAV_COMPONENT]);
65
            $this->_request_data['components'][$node[MIDCOM_NAV_COMPONENT]] = $l10n->get($node[MIDCOM_NAV_COMPONENT]);
66
        }
67 2
        $this->_request_data['topics'][$node[MIDCOM_NAV_FULLURL]] = "{$prefix}{$node[MIDCOM_NAV_NAME]}";
68
69
        // Recurse
70 2
        $prefix .= "{$node[MIDCOM_NAV_NAME]} &rsaquo; ";
71 2
        foreach ($nap->get_nodes($node[MIDCOM_NAV_ID]) as $sub_node) {
72
            $this->search_nodes($sub_node, $nap, $prefix);
73
        }
74
    }
75
76
    /**
77
     * Expand arrays of custom rules to end of query
78
     *
79
     * @param string $final_query reference to the query string to be passed on to the indexer.
80
     * @param mixed $terms array or string to append
81
     */
82 1
    private function append_terms_recursive(string &$final_query, $terms)
83
    {
84 1
        if (is_array($terms)) {
85 1
            foreach ($terms as $term) {
86 1
                $this->append_terms_recursive($final_query, $term);
87
            }
88 1
        } elseif (is_string($terms)) {
89 1
            $final_query .= $terms;
90
        } else {
91
            debug_add('Don\'t know how to handle terms of type: ' . gettype($terms), MIDCOM_LOG_ERROR);
92
            debug_print_r('$terms', $terms);
93
        }
94
    }
95
96
    /**
97
     * Queries the information from the index and prepares to display the result page.
98
     */
99 2
    public function _handler_result(Request $request, array &$data)
100
    {
101 2
        $type = $this->fetch($request, 'type', 'basic');
102
        // If we don't have a query string, relocate to empty search form
103 2
        if (!$request->request->has('query') && !$request->query->has('query')) {
104
            debug_add('$_REQUEST["query"] is not set, relocating back to form', MIDCOM_LOG_INFO);
105
            return new midcom_response_relocate($this->router->generate($type));
106
        }
107 2
        $this->prepare_formdata($type, $request);
108
109 2
        if (   count(explode(' ', $data['query'])) == 1
110 2
            && !str_contains($data['query'], '*')
111 2
            && $this->_config->get('single_term_auto_wildcard')) {
112
            //If there is only one search term append * to the query if auto_wildcard is enabled
113
            $data['query'] .= '*';
114
        }
115
116 2
        if ($type == 'basic') {
117 1
            $indexer = midcom::get()->indexer;
118 1
            $final_query = $data['query'];
119 1
            debug_add("Final query: {$final_query}");
120 1
            $result = $indexer->query($final_query);
121 1
        } elseif ($type == 'advanced') {
122 1
            $result = $this->do_advanced_query($data, $this->fetch($request, 'append_terms'));
123
        } else {
124
            throw new midcom_error_notfound('unknown query type');
125
        }
126
127 2
        $this->process_results($result, (int) $this->fetch($request, 'page', 1));
128 2
        $this->populate_toolbar($request);
129
130 2
        if ($data['document_count'] > 0) {
131
            return $this->show('results');
132
        }
133 2
        return $this->show('no_match');
134
    }
135
136 4
    private function populate_toolbar(Request $request)
137
    {
138 4
        $other_type = ($this->_request_data['type'] == 'advanced') ? 'basic' : 'advanced';
139 4
        $this->_request_data['params'] = '';
140 4
        if ($request->query->count() > 0) {
141 2
            $request->query->set('type', $other_type);
142 2
            $this->_request_data['params'] = '?' . $request->getQueryString();
143
        }
144
145 4
        $url = '';
146 4
        if ($this->_request_data['type'] == 'basic') {
147 2
            $url = 'advanced/';
148
        }
149
150 4
        $this->_view_toolbar->add_item([
151 4
            MIDCOM_TOOLBAR_URL => $url . $this->_request_data['params'],
152 4
            MIDCOM_TOOLBAR_LABEL => $this->_l10n->get($other_type . ' search'),
153 4
            MIDCOM_TOOLBAR_GLYPHICON => 'search',
154 4
        ]);
155
    }
156
157 2
    private function process_results(array $result, int $page)
158
    {
159 2
        $count = count($result);
160 2
        $this->_request_data['document_count'] = $count;
161
162 2
        if ($count == 0) {
163 2
            midcom::get()->cache->content->uncached();
164
        }
165
166 2
        if ($count > 0) {
167
            $results_per_page = $this->_config->get('results_per_page');
168
            $max_pages = ceil($count / $results_per_page);
169
            $page = min($page, $max_pages);
170
            $first_document_id = ($page - 1) * $results_per_page;
171
            $last_document_id = min(($count - 1), (($page * $results_per_page) - 1));
172
173
            $this->_request_data['page'] = $page;
174
            $this->_request_data['max_pages'] = $max_pages;
175
            $this->_request_data['first_document_number'] = $first_document_id + 1;
176
            $this->_request_data['last_document_number'] = $last_document_id + 1;
177
            $this->_request_data['shown_documents'] = $last_document_id - $first_document_id + 1;
178
            $this->_request_data['result'] = array_slice($result, $first_document_id, $results_per_page);
0 ignored issues
show
Bug introduced by
It seems like $results_per_page can also be of type false; however, parameter $length of array_slice() does only seem to accept integer|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

178
            $this->_request_data['result'] = array_slice($result, $first_document_id, /** @scrutinizer ignore-type */ $results_per_page);
Loading history...
179
180
            // Register GUIDs for cache engine
181
            foreach ($this->_request_data['result'] as $doc) {
182
                if (!mgd_is_guid($doc->source)) {
183
                    // Non-Midgard results don't need to go through cache registration
184
                    continue;
185
                }
186
                midcom::get()->cache->content->register($doc->source);
187
            }
188
            reset($this->_request_data['result']);
189
        }
190
    }
191
192
193 1
    private function do_advanced_query(array &$data, $append_terms) : array
194
    {
195 1
        $filter = new midcom_services_indexer_filter_chained;
196 1
        if ($data['lastmodified'] > 0) {
197 1
            $filter->add_filter(new midcom_services_indexer_filter_date('__EDITED', $data['lastmodified'], 0));
198
        }
199
200 1
        $final_query = '';
201 1
        if ($data['query'] != '') {
202 1
            $final_query = (midcom::get()->config->get('indexer_backend') == 'solr') ? $data['query'] : "({$data['query']})";
203
        }
204
205 1
        if ($data['request_topic'] != '') {
206
            $filter->add_filter(new midcom_services_indexer_filter_string('__TOPIC_URL', '"' . $data['request_topic'] . '*"'));
207
        }
208
209 1
        if ($data['component'] != '') {
210
            $filter->add_filter(new midcom_services_indexer_filter_string('__COMPONENT', $data['component']));
211
        }
212
213
        // Way to add very custom terms
214 1
        if ($append_terms) {
215 1
            $this->append_terms_recursive($final_query, $append_terms);
216
        }
217
218 1
        debug_add("Final query: {$final_query}");
219 1
        $indexer = midcom::get()->indexer;
220
221 1
        if ($filter->count() == 0) {
222
            $filter = null;
223
        }
224 1
        return $indexer->query($final_query, $filter);
225
    }
226
227
    /**
228
     * Prepare OpenSearch data file for browser search bar integration.
229
     */
230 1
    public function _handler_opensearchdescription(array &$data)
231
    {
232 1
        midcom::get()->cache->content->content_type("application/opensearchdescription+xml; charset=UTF-8");
233 1
        midcom::get()->skip_page_style = true;
234
235 1
        $data['node'] = $this->_topic;
236 1
        return $this->show('opensearch_description');
237
    }
238
}
239