Passed
Push — master ( 400e9c...9727f8 )
by Andreas
24:36
created

append_terms_recursive()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.25

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 4
nop 2
dl 0
loc 11
ccs 6
cts 8
cp 0.75
crap 4.25
rs 10
c 0
b 0
f 0
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\Request;
10
11
/**
12
 * Search handler
13
 *
14
 * @package midcom.helper.search
15
 */
16
class midcom_helper_search_handler_search extends midcom_baseclasses_components_handler
17
{
18
    /**
19
     * Search form handler, nothing to do here.
20
     *
21
     * It uses the handler ID to distinguish between basic and advanced search forms.
22
     */
23 2
    public function _handler_searchform(Request $request, string $handler_id)
24
    {
25 2
        $this->prepare_formdata($handler_id);
26 2
        $this->populate_toolbar($request);
27 2
        return $this->show('search_form');
28
    }
29
30 4
    private function prepare_formdata($handler_id)
31
    {
32 4
        $this->_request_data['query'] = (array_key_exists('query', $_REQUEST) ? $_REQUEST['query'] : '');
33 4
        if ($handler_id === 'advanced') {
34 2
            $this->_request_data['request_topic'] = (array_key_exists('topic', $_REQUEST) ? $_REQUEST['topic'] : '');
35 2
            $this->_request_data['component'] = (array_key_exists('component', $_REQUEST) ? $_REQUEST['component'] : '');
36 2
            $this->_request_data['lastmodified'] = (array_key_exists('lastmodified', $_REQUEST) ? ((integer) $_REQUEST['lastmodified']) : 0);
37
38 2
            $this->_request_data['topics'] = ['' => $this->_l10n->get('search anywhere')];
39 2
            $this->_request_data['components'] = ['' => $this->_l10n->get('search all content types')];
40
41 2
            $nap = new midcom_helper_nav();
42 2
            $this->search_nodes($nap->get_root_node(), $nap, '');
43
        }
44 4
        $this->_request_data['type'] = $handler_id;
45 4
    }
46
47
    /**
48
     * Prepare the topic and component listings, this is a bit work intensive though,
49
     * we need to traverse everything.
50
     */
51 2
    private function search_nodes($node_id, midcom_helper_nav $nap, $prefix)
52
    {
53 2
        $node = $nap->get_node($node_id);
54
55 2
        if (   !array_key_exists($node[MIDCOM_NAV_COMPONENT], $this->_request_data['components'])
56 2
            && $node[MIDCOM_NAV_COMPONENT] != 'midcom.helper.search') {
57
            $l10n = $this->_i18n->get_l10n($node[MIDCOM_NAV_COMPONENT]);
58
            $this->_request_data['components'][$node[MIDCOM_NAV_COMPONENT]] = $l10n->get($node[MIDCOM_NAV_COMPONENT]);
59
        }
60 2
        $this->_request_data['topics'][$node[MIDCOM_NAV_FULLURL]] = "{$prefix}{$node[MIDCOM_NAV_NAME]}";
61
62
        // Recurse
63 2
        $prefix .= "{$node[MIDCOM_NAV_NAME]} &rsaquo; ";
64 2
        $subnodes = $nap->list_nodes($node_id);
65 2
        foreach ($subnodes as $sub_id) {
66
            $this->search_nodes($sub_id, $nap, $prefix);
67
        }
68 2
    }
69
70
    /**
71
     * Expand arrays of custom rules to end of query
72
     *
73
     * @param string $final_query reference to the query string to be passed on to the indexer.
74
     * @param mixed $terms array or string to append
75
     */
76 1
    private function append_terms_recursive(string &$final_query, $terms)
77
    {
78 1
        if (is_array($terms)) {
79 1
            foreach ($terms as $term) {
80 1
                $this->append_terms_recursive($final_query, $term);
81
            }
82 1
        } elseif (is_string($terms)) {
83 1
            $final_query .= $terms;
84
        } else {
85
            debug_add('Don\'t know how to handle terms of type: ' . gettype($terms), MIDCOM_LOG_ERROR);
86
            debug_print_r('$terms', $terms);
87
        }
88 1
    }
89
90
    /**
91
     * Queries the information from the index and prepares to display the result page.
92
     */
93 2
    public function _handler_result(Request $request, array &$data)
94
    {
95 2
        $this->prepare_query_data();
96
        // If we don't have a query string, relocate to empty search form
97 2
        if (!isset($_REQUEST['query'])) {
98
            debug_add('$_REQUEST["query"] is not set, relocating back to form', MIDCOM_LOG_INFO);
99
            $url = ($_REQUEST['type'] == 'basic') ? '' : 'advanced/';
100
            return new midcom_response_relocate($url);
101
        }
102 2
        $this->prepare_formdata($_REQUEST['type']);
103
104 2
        if (   count(explode(' ', $data['query'])) == 1
105 2
            && strpos($data['query'], '*') === false
106 2
            && $this->_config->get('single_term_auto_wildcard')) {
107
            //If there is only one search term append * to the query if auto_wildcard is enabled
108
            $data['query'] .= '*';
109
        }
110
111 2
        if ($data['type'] == 'basic') {
112 1
            $indexer = midcom::get()->indexer;
113 1
            $final_query = $data['query'];
114 1
            debug_add("Final query: {$final_query}");
115 1
            $result = $indexer->query($final_query);
116 1
        } elseif ($data['type'] == 'advanced') {
117 1
            $result = $this->do_advanced_query($data);
118
        } else {
119
            throw new midcom_error_notfound('unknown query type');
120
        }
121
122 2
        $this->process_results($result);
123 2
        $this->populate_toolbar($request);
124 2
    }
125
126 4
    private function populate_toolbar(Request $request)
127
    {
128 4
        $other_type = ($this->_request_data['type'] == 'advanced') ? 'basic' : 'advanced';
129 4
        $this->_request_data['params'] = '';
130 4
        if ($request->query->count() > 0) {
131
            $request->query->set('type', $other_type);
132
            $this->_request_data['params'] = '?' . $request->getQueryString();
133
        }
134
135 4
        $url = '';
136 4
        if ($this->_request_data['type'] == 'basic') {
137 2
            $url = 'advanced/';
138
        }
139
140 4
        $this->_view_toolbar->add_item([
141 4
            MIDCOM_TOOLBAR_URL => $url . $this->_request_data['params'],
142 4
            MIDCOM_TOOLBAR_LABEL => $this->_l10n->get($other_type . ' search'),
143 4
            MIDCOM_TOOLBAR_GLYPHICON => 'search',
144
        ]);
145 4
    }
146
147 2
    private function process_results(array $result)
148
    {
149 2
        $count = count($result);
150 2
        $this->_request_data['document_count'] = $count;
151
152 2
        if ($count == 0) {
153 2
            midcom::get()->cache->content->uncached();
154
        }
155
156 2
        if ($count > 0) {
157
            $results_per_page = $this->_config->get('results_per_page');
158
            $max_pages = ceil($count / $results_per_page);
159
            $page = min($_REQUEST['page'], $max_pages);
160
            $first_document_id = ($page - 1) * $results_per_page;
161
            $last_document_id = min(($count - 1), (($page * $results_per_page) - 1));
162
163
            $this->_request_data['page'] = $page;
164
            $this->_request_data['max_pages'] = $max_pages;
165
            $this->_request_data['first_document_number'] = $first_document_id + 1;
166
            $this->_request_data['last_document_number'] = $last_document_id + 1;
167
            $this->_request_data['shown_documents'] = $last_document_id - $first_document_id + 1;
168
            $this->_request_data['results_per_page'] = $results_per_page;
169
            $this->_request_data['all_results'] =& $result;
170
            $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, 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

170
            $this->_request_data['result'] = array_slice($result, $first_document_id, /** @scrutinizer ignore-type */ $results_per_page);
Loading history...
171
172
            // Register GUIDs for cache engine
173
            foreach ($this->_request_data['result'] as $doc) {
174
                if (   !isset($doc->source)
175
                    || !mgd_is_guid($doc->source)) {
176
                    // Non-Midgard results don't need to go through cache registration
177
                    continue;
178
                }
179
                midcom::get()->cache->content->register($doc->source);
180
            }
181
            reset($this->_request_data['result']);
182
        }
183 2
    }
184
185
    /**
186
     * Sane defaults for REQUEST vars
187
     */
188 2
    private function prepare_query_data()
189
    {
190
        $defaults = [
191 2
            'type' => 'basic',
192
            'page' => 1,
193
            'component' => '',
194
            'topic' => '',
195
            'lastmodified' => 0
196
        ];
197
198 2
        $_REQUEST = array_merge($defaults, $_REQUEST);
199 2
    }
200
201 1
    private function do_advanced_query(array &$data) : array
202
    {
203 1
        $data['request_topic'] = trim($_REQUEST['topic']);
204 1
        $data['component'] = trim($_REQUEST['component']);
205 1
        $data['lastmodified'] = (integer) trim($_REQUEST['lastmodified']);
206 1
        $filter = new midcom_services_indexer_filter_chained;
207 1
        if ($data['lastmodified'] > 0) {
208 1
            $filter->add_filter(new midcom_services_indexer_filter_date('__EDITED', $data['lastmodified'], 0));
209
        }
210
211 1
        $final_query = '';
212 1
        if ($data['query'] != '') {
213 1
            $final_query = (midcom::get()->config->get('indexer_backend') == 'solr') ? $data['query'] : "({$data['query']})";
214
        }
215
216 1
        if ($data['request_topic'] != '') {
217
            $filter->add_filter(new midcom_services_indexer_filter_string('__TOPIC_URL', '"' . $data['request_topic'] . '*"'));
218
        }
219
220 1
        if ($data['component'] != '') {
221
            $filter->add_filter(new midcom_services_indexer_filter_string('__COMPONENT', $data['component']));
222
        }
223
224
        // Way to add very custom terms
225 1
        if (isset($_REQUEST['append_terms'])) {
226 1
            $this->append_terms_recursive($final_query, $_REQUEST['append_terms']);
227
        }
228
229 1
        debug_add("Final query: {$final_query}");
230 1
        $indexer = midcom::get()->indexer;
231
232 1
        if ($filter->count() == 0) {
233
            $filter = null;
234
        }
235 1
        return $indexer->query($final_query, $filter);
236
    }
237
238
    /**
239
     * Displays the resultset.
240
     *
241
     * @param mixed $handler_id The ID of the handler.
242
     * @param array $data The local request data.
243
     */
244 2
    public function _show_result($handler_id, array &$data)
245
    {
246 2
        if ($data['document_count'] > 0) {
247
            midcom_show_style('results');
248
        } else {
249 2
            midcom_show_style('no_match');
250
        }
251 2
    }
252
253
    /**
254
     * Prepare OpenSearch data file for browser search bar integration.
255
     */
256 1
    public function _handler_opensearchdescription(array &$data)
257
    {
258 1
        midcom::get()->cache->content->content_type("application/opensearchdescription+xml; charset=UTF-8");
259 1
        midcom::get()->skip_page_style = true;
260
261 1
        $data['node'] = $this->_topic;
262 1
        return $this->show('opensearch_description');
263
    }
264
}
265