Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.14% covered (success)
97.14%
34 / 35
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
QueryBuilder
97.14% covered (success)
97.14%
34 / 35
80.00% covered (warning)
80.00%
4 / 5
14
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 build
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 abstractQueryToString
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 queryGroupToString
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
7.01
 queryToString
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3/**
4 * EIT QueryBuilder.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2010.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  Search
25 * @author   Julia Bauder <bauderj@grinnell.edu>
26 * @author   Andrew S. Nagy <vufind-tech@lists.sourceforge.net>
27 * @author   David Maus <maus@hab.de>
28 * @author   Demian Katz <demian.katz@villanova.edu>
29 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
30 * @link     https://vufind.org
31 */
32
33namespace VuFindSearch\Backend\EIT;
34
35use VuFindSearch\ParamBag;
36use VuFindSearch\Query\AbstractQuery;
37use VuFindSearch\Query\Query;
38use VuFindSearch\Query\QueryGroup;
39
40use function count;
41
42/**
43 * EIT QueryBuilder.
44 * Largely copied from the WorldCat QueryBuilder
45 *
46 * @category VuFind
47 * @package  Search
48 * @author   Julia Bauder <bauderj@grinnell.edu>
49 * @author   Andrew S. Nagy <vufind-tech@lists.sourceforge.net>
50 * @author   David Maus <maus@hab.de>
51 * @author   Demian Katz <demian.katz@villanova.edu>
52 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
53 * @link     https://vufind.org
54 */
55class QueryBuilder
56{
57    /// Public API
58
59    /**
60     * Constructor
61     */
62    public function __construct()
63    {
64    }
65
66    /**
67     * Return EIT search parameters based on a user query and params.
68     *
69     * @param AbstractQuery $query  User query
70     * @param ?ParamBag     $params Search backend parameters
71     *
72     * @return ParamBag
73     *
74     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
75     */
76    public function build(AbstractQuery $query, ?ParamBag $params = null)
77    {
78        // Build base query
79        $queryStr = $this->abstractQueryToString($query);
80
81        // Send back results
82        $newParams = new ParamBag();
83        $newParams->set('query', $queryStr);
84        return $newParams;
85    }
86
87    /// Internal API
88
89    /**
90     * Convert an AbstractQuery object to a query string.
91     *
92     * @param AbstractQuery $query Query to convert
93     *
94     * @return string
95     */
96    protected function abstractQueryToString(AbstractQuery $query)
97    {
98        if ($query instanceof Query) {
99            return $this->queryToString($query);
100        } else {
101            return $this->queryGroupToString($query);
102        }
103    }
104
105    /**
106     * Convert a QueryGroup object to a query string.
107     *
108     * @param QueryGroup $query QueryGroup to convert
109     *
110     * @return string
111     */
112    protected function queryGroupToString(QueryGroup $query)
113    {
114        $groups = $excludes = [];
115
116        foreach ($query->getQueries() as $params) {
117            // Advanced Search
118            if ($params instanceof QueryGroup) {
119                $thisGroup = [];
120                // Process each search group
121                foreach ($params->getQueries() as $group) {
122                    // Build this group individually as a basic search
123                    $thisGroup[] = $this->abstractQueryToString($group);
124                }
125                // Is this an exclusion (NOT) group or a normal group?
126                if ($params->isNegated()) {
127                    $excludes[] = implode(' OR ', $thisGroup);
128                } else {
129                    $groups[]
130                        = implode(' ' . $params->getOperator() . ' ', $thisGroup);
131                }
132            } else {
133                // Basic Search
134                $groups[] = $this->queryToString($params);
135            }
136        }
137
138        // Put our advanced search together
139        $queryStr = '';
140        if (count($groups) > 0) {
141            $queryStr
142                .= '(' . implode(') ' . $query->getOperator() . ' (', $groups) . ')';
143        }
144        // and concatenate exclusion after that
145        if (count($excludes) > 0) {
146            $queryStr .= ' NOT ((' . implode(') OR (', $excludes) . '))';
147        }
148
149        return $queryStr;
150    }
151
152    /**
153     * Convert a single Query object to a query string.
154     *
155     * @param Query $query Query to convert
156     *
157     * @return string
158     */
159    protected function queryToString(Query $query)
160    {
161        // Clean and validate input:
162        $index = $query->getHandler();
163        if (empty($index)) {
164            // No handler?  Just accept query string as-is; no modifications needed.
165            return $query->getString();
166        }
167        $lookfor = $query->getString();
168
169        // The index may contain multiple parts -- we want to search all listed index
170        // fields:
171        $index = explode(':', $index);
172        $clauses = [];
173        foreach ($index as $currentIndex) {
174            $clauses[] = "{$currentIndex} {$lookfor}";
175        }
176
177        return '(' . implode(' OR ', $clauses) . ')';
178    }
179}