Skip to content

Commit

Permalink
Merge branch 'develop-5'
Browse files Browse the repository at this point in the history
  • Loading branch information
jschultze committed Mar 2, 2020
2 parents 5781f0f + 97aee32 commit 3e51df9
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
//use DependentWorks\DependentWorks;
use VuFind\AjaxHandler\AbstractBase;
use VuFind\Search\Results\PluginManager as ResultsManager;
use VuFind\I18n\Translator\TranslatorAwareInterface;
use Zend\Http\PhpEnvironment\Request;
use Zend\Mvc\Controller\Plugin\Params;
use Zend\Stdlib\Parameters;
Expand All @@ -44,8 +45,10 @@
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link http://vufind.org/wiki/vufind2:building_a_controller Wiki
*/
class GetDependentWorks extends AbstractBase
class GetDependentWorks extends AbstractBase implements TranslatorAwareInterface
{
use \VuFind\I18n\Translator\TranslatorAwareTrait;

/**
* ZF configuration
*
Expand Down Expand Up @@ -84,15 +87,26 @@ public function handleRequest(Params $params)
{
$limit = $this->config['Global']['limit'] ?? 1;
$sortFlag = $this->config['Global']['sort'] ?? SORT_REGULAR;
$switchToRegularSearch = ($this->config['Global']['switch_to_regular_search'] == 'y');

$ppn = $params->fromQuery('ppn');
if (empty($ppn)) {
return $this->formatResponse([]);
}
$backend = $params->fromQuery('source', DEFAULT_SEARCH_BACKEND);
$results = $this->resultsManager->get($backend);
$results->getOptions()->setLimitOptions([20, 400]);
$results->getOptions()->setLimitOptions([$limit, $limit]);
$paramsObj = $results->getParams();
$paramsObj->initFromRequest(new Parameters(['lookfor' => 'hierarchy_top_id:'.$ppn.' -id:'.$ppn, 'limit' => $limit]));
$paramsObj->initFromRequest(new Parameters(['lookfor' => 'hierarchy_top_id:'.$ppn.' -id:'.$ppn]));

$records = $results->getResults();
$resultTotal = $results->getResultTotal();

if ($switchToRegularSearch && $resultTotal > $limit) {
$resultString = $resultTotal . ' ' . $this->translate('results') . ': ' . $this->translate('show all');
return $this->formatResponse([['resultString' => (string) $resultString]]);
}

$data = [];
foreach ($records as $i => $record) {
$dependentWorksData = $record->getMarcData('DependentWorksData');
Expand Down
53 changes: 1 addition & 52 deletions module/DismaxMunge/src/DismaxMunge/Backend/Solr/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@
*/
class QueryBuilder extends \VuFindSearch\Backend\Solr\QueryBuilder implements QueryBuilderInterface
{
/// Public API


/**
* Set query builder search specs.
*
Expand Down Expand Up @@ -108,9 +105,7 @@ public function build(AbstractQuery $query)
$highlight = !empty($this->fieldsToHighlight);

if ($handler = $this->getSearchHandler($finalQuery->getHandler(), $string)) {
if ($handler->hasDismax()) {
$string = array_pop($handler->mungeValues($string, false));
}
$string = $handler->preprocessQueryString($string);
if (!$handler->hasExtendedDismax()
&& $this->getLuceneHelper()->containsAdvancedLuceneSyntax($string)
) {
Expand Down Expand Up @@ -146,50 +141,4 @@ public function build(AbstractQuery $query)
$params->set('q', $string);
return $params;
}

/**
* Reduce components of query group to a search string of a simple query.
*
* This function implements the recursive reduction of a query group.
*
* @param AbstractQuery $component Component
*
* @return string
*
* @see self::reduceQueryGroup()
*/
protected function reduceQueryGroupComponents(AbstractQuery $component)
{
if ($component instanceof QueryGroup) {
$reduced = array_map(
[$this, 'reduceQueryGroupComponents'], $component->getQueries()
);
$searchString = $component->isNegated() ? 'NOT ' : '';
$reduced = array_filter(
$reduced,
function ($s) {
return '' !== $s;
}
);
if ($reduced) {
$searchString .= sprintf(
'(%s)', implode(" {$component->getOperator()} ", $reduced)
);
}
} else {
$searchString = $this->getNormalizedQueryString($component);
$searchHandler = $this->getSearchHandler(
$component->getHandler(),
$searchString
);
if ($searchHandler && $searchHandler->hasDismax()) {
$searchString = array_pop($searchHandler->mungeValues($searchString, false));
}
if ($searchHandler && '' !== $searchString) {
$searchString
= $this->createSearchString($searchString, $searchHandler);
}
}
return $searchString;
}
}
190 changes: 188 additions & 2 deletions module/DismaxMunge/src/DismaxMunge/Backend/Solr/SearchHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,194 @@
*/
class SearchHandler extends \VuFindSearch\Backend\Solr\SearchHandler
{
public function mungeValues($search, $tokenize = true)
/**
* Known configuration keys.
*
* @var array
*/
protected static $configKeys = [
'CustomMunge', 'DismaxFields', 'DismaxHandler', 'QueryFields',
'DismaxParams', 'FilterQuery', 'DismaxMunge'
];

/**
* Constructor.
*
* @param array $spec Search handler specification
* @param string $defaultDismaxHandler Default dismax handler (if no
* DismaxHandler set in specs).
*
* @return void
*/
public function __construct(array $spec, $defaultDismaxHandler = 'dismax')
{
foreach (self::$configKeys as $key) {
$this->specs[$key] = $spec[$key] ?? [];
}
// Set dismax handler to default if not specified:
if (empty($this->specs['DismaxHandler'])) {
$this->specs['DismaxHandler'] = $defaultDismaxHandler;
}
// Set default mm handler if necessary:
$this->setDefaultMustMatch();
}

/**
* Apply standard pre-processing to the query string.
*
* @param string $search Search string
*
* @return string
*/
public function preprocessQueryString($search)
{
// Apply Dismax munging, if required:
if ($this->hasDismax()) {
return $this->dismaxMunge($search);
}
return $search;
}

/**
* Return the munge values for specified search string.
*
* If optional argument $tokenize is true tokenize the search string.
*
* @param string $search Search string
* @param bool $tokenize Tokenize the search string?
*
* @return string
*/
protected function mungeValues($search, $tokenize = true)
{
if ($tokenize) {
$tokens = $this->tokenize($search);
$mungeValues = [
'onephrase' => sprintf(
'"%s"', str_replace('"', '', implode(' ', $tokens))
),
'and' => implode(' AND ', $tokens),
'or' => implode(' OR ', $tokens),
'identity' => $search,
];
} else {
$mungeValues = [
'and' => $search,
'or' => $search,
];
// If we're skipping tokenization, we just want to pass $lookfor through
// unmodified (it's probably an advanced search that won't benefit from
// tokenization). We'll just set all possible values to the same thing,
// except that we'll try to do the "one phrase" in quotes if possible.
// IMPORTANT: If we detect a boolean NOT, we MUST omit the quotes. We
// also omit quotes if the phrase is already quoted or if there is no
// whitespace (in which case phrase searching is pointless and might
// interfere with wildcard behavior):
if (strstr($search, '"') || strstr($search, ' NOT ')
|| !preg_match('/\s/', $search)
) {
$mungeValues['onephrase'] = $search;
} else {
$mungeValues['onephrase'] = sprintf('"%s"', $search);
}
}

$mungeValues['identity'] = $search;

foreach ($this->specs['CustomMunge'] as $mungeName => $mungeOps) {
$mungeValues[$mungeName] = $search;
foreach ($mungeOps as $operation) {
$mungeValues[$mungeName]
= $this->customMunge($mungeValues[$mungeName], $operation);
}
}
return $mungeValues;
}

/**
* Apply custom search string munging to a Dismax query.
*
* @param string $search searchstring
*
* @return string
*/
protected function dismaxMunge($search)
{
foreach ($this->specs['DismaxMunge'] as $operation) {
$search = $this->customMunge($search, $operation);
}
return $search;
}

/**
* Apply a munge operation to a search string.
*
* @param string $string string to munge
* @param array $operation munge operation
*
* @return string
*/
protected function customMunge($string, $operation)
{
switch ($operation[0]) {
case 'append':
$string .= $operation[1];
break;
case 'lowercase':
$string = strtolower($string);
break;
case 'preg_replace':
$string = preg_replace(
$operation[1], $operation[2], $string
);
break;
case 'ucfirst':
$string = ucfirst($string);
break;
case 'uppercase':
$string = strtoupper($string);
break;
default:
throw new \InvalidArgumentException(
sprintf('Unknown munge operation: %s', $operation[0])
);
}
return $string;
}

/**
* Return query string for specified search string.
*
* If optional argument $advanced is true the search string contains
* advanced lucene query syntax.
*
* @param string $search Search string
* @param bool $advanced Is the search an advanced search string?
*
* @return string
*/
protected function createQueryString($search, $advanced = false)
{
return parent::mungeValues($search, $tokenize);
// If this is a basic query and we have Dismax settings (or if we have
// Extended Dismax available), let's build a Dismax subquery to avoid
// some of the ugly side effects of our Lucene query generation logic.
if (($this->hasExtendedDismax() || !$advanced) && $this->hasDismax()) {
$query = $this->dismaxSubquery(
$this->dismaxMunge($search)
);
} else {
$mungeRules = $this->mungeRules();
// Do not munge w/o rules
if ($mungeRules) {
$mungeValues = $this->mungeValues($search, !$advanced);
$query = $this->munge($mungeRules, $mungeValues);
} else {
$query = $search;
}
}
if ($this->hasFilterQuery()) {
$query = sprintf('(%s) AND (%s)', $query, $this->getFilterQuery());
}
return "($query)";
}
}
Loading

0 comments on commit 3e51df9

Please sign in to comment.