Skip to content

Commit 3e51df9

Browse files
committed
Merge branch 'develop-5'
2 parents 5781f0f + 97aee32 commit 3e51df9

File tree

12 files changed

+364
-101
lines changed

12 files changed

+364
-101
lines changed

module/DependentWorks/src/DependentWorks/AjaxHandler/GetDependentWorks.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
//use DependentWorks\DependentWorks;
3131
use VuFind\AjaxHandler\AbstractBase;
3232
use VuFind\Search\Results\PluginManager as ResultsManager;
33+
use VuFind\I18n\Translator\TranslatorAwareInterface;
3334
use Zend\Http\PhpEnvironment\Request;
3435
use Zend\Mvc\Controller\Plugin\Params;
3536
use Zend\Stdlib\Parameters;
@@ -44,8 +45,10 @@
4445
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
4546
* @link http://vufind.org/wiki/vufind2:building_a_controller Wiki
4647
*/
47-
class GetDependentWorks extends AbstractBase
48+
class GetDependentWorks extends AbstractBase implements TranslatorAwareInterface
4849
{
50+
use \VuFind\I18n\Translator\TranslatorAwareTrait;
51+
4952
/**
5053
* ZF configuration
5154
*
@@ -84,15 +87,26 @@ public function handleRequest(Params $params)
8487
{
8588
$limit = $this->config['Global']['limit'] ?? 1;
8689
$sortFlag = $this->config['Global']['sort'] ?? SORT_REGULAR;
90+
$switchToRegularSearch = ($this->config['Global']['switch_to_regular_search'] == 'y');
8791

8892
$ppn = $params->fromQuery('ppn');
93+
if (empty($ppn)) {
94+
return $this->formatResponse([]);
95+
}
8996
$backend = $params->fromQuery('source', DEFAULT_SEARCH_BACKEND);
9097
$results = $this->resultsManager->get($backend);
91-
$results->getOptions()->setLimitOptions([20, 400]);
98+
$results->getOptions()->setLimitOptions([$limit, $limit]);
9299
$paramsObj = $results->getParams();
93-
$paramsObj->initFromRequest(new Parameters(['lookfor' => 'hierarchy_top_id:'.$ppn.' -id:'.$ppn, 'limit' => $limit]));
100+
$paramsObj->initFromRequest(new Parameters(['lookfor' => 'hierarchy_top_id:'.$ppn.' -id:'.$ppn]));
94101

95102
$records = $results->getResults();
103+
$resultTotal = $results->getResultTotal();
104+
105+
if ($switchToRegularSearch && $resultTotal > $limit) {
106+
$resultString = $resultTotal . ' ' . $this->translate('results') . ': ' . $this->translate('show all');
107+
return $this->formatResponse([['resultString' => (string) $resultString]]);
108+
}
109+
96110
$data = [];
97111
foreach ($records as $i => $record) {
98112
$dependentWorksData = $record->getMarcData('DependentWorksData');

module/DismaxMunge/src/DismaxMunge/Backend/Solr/QueryBuilder.php

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@
5050
*/
5151
class QueryBuilder extends \VuFindSearch\Backend\Solr\QueryBuilder implements QueryBuilderInterface
5252
{
53-
/// Public API
54-
55-
5653
/**
5754
* Set query builder search specs.
5855
*
@@ -108,9 +105,7 @@ public function build(AbstractQuery $query)
108105
$highlight = !empty($this->fieldsToHighlight);
109106

110107
if ($handler = $this->getSearchHandler($finalQuery->getHandler(), $string)) {
111-
if ($handler->hasDismax()) {
112-
$string = array_pop($handler->mungeValues($string, false));
113-
}
108+
$string = $handler->preprocessQueryString($string);
114109
if (!$handler->hasExtendedDismax()
115110
&& $this->getLuceneHelper()->containsAdvancedLuceneSyntax($string)
116111
) {
@@ -146,50 +141,4 @@ public function build(AbstractQuery $query)
146141
$params->set('q', $string);
147142
return $params;
148143
}
149-
150-
/**
151-
* Reduce components of query group to a search string of a simple query.
152-
*
153-
* This function implements the recursive reduction of a query group.
154-
*
155-
* @param AbstractQuery $component Component
156-
*
157-
* @return string
158-
*
159-
* @see self::reduceQueryGroup()
160-
*/
161-
protected function reduceQueryGroupComponents(AbstractQuery $component)
162-
{
163-
if ($component instanceof QueryGroup) {
164-
$reduced = array_map(
165-
[$this, 'reduceQueryGroupComponents'], $component->getQueries()
166-
);
167-
$searchString = $component->isNegated() ? 'NOT ' : '';
168-
$reduced = array_filter(
169-
$reduced,
170-
function ($s) {
171-
return '' !== $s;
172-
}
173-
);
174-
if ($reduced) {
175-
$searchString .= sprintf(
176-
'(%s)', implode(" {$component->getOperator()} ", $reduced)
177-
);
178-
}
179-
} else {
180-
$searchString = $this->getNormalizedQueryString($component);
181-
$searchHandler = $this->getSearchHandler(
182-
$component->getHandler(),
183-
$searchString
184-
);
185-
if ($searchHandler && $searchHandler->hasDismax()) {
186-
$searchString = array_pop($searchHandler->mungeValues($searchString, false));
187-
}
188-
if ($searchHandler && '' !== $searchString) {
189-
$searchString
190-
= $this->createSearchString($searchString, $searchHandler);
191-
}
192-
}
193-
return $searchString;
194-
}
195144
}

module/DismaxMunge/src/DismaxMunge/Backend/Solr/SearchHandler.php

Lines changed: 188 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,194 @@
4646
*/
4747
class SearchHandler extends \VuFindSearch\Backend\Solr\SearchHandler
4848
{
49-
public function mungeValues($search, $tokenize = true)
49+
/**
50+
* Known configuration keys.
51+
*
52+
* @var array
53+
*/
54+
protected static $configKeys = [
55+
'CustomMunge', 'DismaxFields', 'DismaxHandler', 'QueryFields',
56+
'DismaxParams', 'FilterQuery', 'DismaxMunge'
57+
];
58+
59+
/**
60+
* Constructor.
61+
*
62+
* @param array $spec Search handler specification
63+
* @param string $defaultDismaxHandler Default dismax handler (if no
64+
* DismaxHandler set in specs).
65+
*
66+
* @return void
67+
*/
68+
public function __construct(array $spec, $defaultDismaxHandler = 'dismax')
69+
{
70+
foreach (self::$configKeys as $key) {
71+
$this->specs[$key] = $spec[$key] ?? [];
72+
}
73+
// Set dismax handler to default if not specified:
74+
if (empty($this->specs['DismaxHandler'])) {
75+
$this->specs['DismaxHandler'] = $defaultDismaxHandler;
76+
}
77+
// Set default mm handler if necessary:
78+
$this->setDefaultMustMatch();
79+
}
80+
81+
/**
82+
* Apply standard pre-processing to the query string.
83+
*
84+
* @param string $search Search string
85+
*
86+
* @return string
87+
*/
88+
public function preprocessQueryString($search)
89+
{
90+
// Apply Dismax munging, if required:
91+
if ($this->hasDismax()) {
92+
return $this->dismaxMunge($search);
93+
}
94+
return $search;
95+
}
96+
97+
/**
98+
* Return the munge values for specified search string.
99+
*
100+
* If optional argument $tokenize is true tokenize the search string.
101+
*
102+
* @param string $search Search string
103+
* @param bool $tokenize Tokenize the search string?
104+
*
105+
* @return string
106+
*/
107+
protected function mungeValues($search, $tokenize = true)
108+
{
109+
if ($tokenize) {
110+
$tokens = $this->tokenize($search);
111+
$mungeValues = [
112+
'onephrase' => sprintf(
113+
'"%s"', str_replace('"', '', implode(' ', $tokens))
114+
),
115+
'and' => implode(' AND ', $tokens),
116+
'or' => implode(' OR ', $tokens),
117+
'identity' => $search,
118+
];
119+
} else {
120+
$mungeValues = [
121+
'and' => $search,
122+
'or' => $search,
123+
];
124+
// If we're skipping tokenization, we just want to pass $lookfor through
125+
// unmodified (it's probably an advanced search that won't benefit from
126+
// tokenization). We'll just set all possible values to the same thing,
127+
// except that we'll try to do the "one phrase" in quotes if possible.
128+
// IMPORTANT: If we detect a boolean NOT, we MUST omit the quotes. We
129+
// also omit quotes if the phrase is already quoted or if there is no
130+
// whitespace (in which case phrase searching is pointless and might
131+
// interfere with wildcard behavior):
132+
if (strstr($search, '"') || strstr($search, ' NOT ')
133+
|| !preg_match('/\s/', $search)
134+
) {
135+
$mungeValues['onephrase'] = $search;
136+
} else {
137+
$mungeValues['onephrase'] = sprintf('"%s"', $search);
138+
}
139+
}
140+
141+
$mungeValues['identity'] = $search;
142+
143+
foreach ($this->specs['CustomMunge'] as $mungeName => $mungeOps) {
144+
$mungeValues[$mungeName] = $search;
145+
foreach ($mungeOps as $operation) {
146+
$mungeValues[$mungeName]
147+
= $this->customMunge($mungeValues[$mungeName], $operation);
148+
}
149+
}
150+
return $mungeValues;
151+
}
152+
153+
/**
154+
* Apply custom search string munging to a Dismax query.
155+
*
156+
* @param string $search searchstring
157+
*
158+
* @return string
159+
*/
160+
protected function dismaxMunge($search)
161+
{
162+
foreach ($this->specs['DismaxMunge'] as $operation) {
163+
$search = $this->customMunge($search, $operation);
164+
}
165+
return $search;
166+
}
167+
168+
/**
169+
* Apply a munge operation to a search string.
170+
*
171+
* @param string $string string to munge
172+
* @param array $operation munge operation
173+
*
174+
* @return string
175+
*/
176+
protected function customMunge($string, $operation)
177+
{
178+
switch ($operation[0]) {
179+
case 'append':
180+
$string .= $operation[1];
181+
break;
182+
case 'lowercase':
183+
$string = strtolower($string);
184+
break;
185+
case 'preg_replace':
186+
$string = preg_replace(
187+
$operation[1], $operation[2], $string
188+
);
189+
break;
190+
case 'ucfirst':
191+
$string = ucfirst($string);
192+
break;
193+
case 'uppercase':
194+
$string = strtoupper($string);
195+
break;
196+
default:
197+
throw new \InvalidArgumentException(
198+
sprintf('Unknown munge operation: %s', $operation[0])
199+
);
200+
}
201+
return $string;
202+
}
203+
204+
/**
205+
* Return query string for specified search string.
206+
*
207+
* If optional argument $advanced is true the search string contains
208+
* advanced lucene query syntax.
209+
*
210+
* @param string $search Search string
211+
* @param bool $advanced Is the search an advanced search string?
212+
*
213+
* @return string
214+
*/
215+
protected function createQueryString($search, $advanced = false)
50216
{
51-
return parent::mungeValues($search, $tokenize);
217+
// If this is a basic query and we have Dismax settings (or if we have
218+
// Extended Dismax available), let's build a Dismax subquery to avoid
219+
// some of the ugly side effects of our Lucene query generation logic.
220+
if (($this->hasExtendedDismax() || !$advanced) && $this->hasDismax()) {
221+
$query = $this->dismaxSubquery(
222+
$this->dismaxMunge($search)
223+
);
224+
} else {
225+
$mungeRules = $this->mungeRules();
226+
// Do not munge w/o rules
227+
if ($mungeRules) {
228+
$mungeValues = $this->mungeValues($search, !$advanced);
229+
$query = $this->munge($mungeRules, $mungeValues);
230+
} else {
231+
$query = $search;
232+
}
233+
}
234+
if ($this->hasFilterQuery()) {
235+
$query = sprintf('(%s) AND (%s)', $query, $this->getFilterQuery());
236+
}
237+
return "($query)";
52238
}
53239
}

0 commit comments

Comments
 (0)