/** * Build a string for onscreen display showing the * query used in the search (not the filters). * * @return string user friendly version of 'query' */ public function getDisplayQuery() { // For display purposes, undo the query manipulation performed above // in initBasicSearch(): $q = parent::getDisplayQuery(); return str_replace('\\"', '"', substr($q, 1, -1)); }
/** * This test performs Solr searches using multifacets and checks whether they work * as expected (adding 'OR something' to filter query should increase count of returned records * in at least one case). */ public function testMultiFacetsSearch() { //configuration $solr = $this->getServiceManager()->get('VuFind\\Search\\BackendManager')->get('Solr'); $connector = $solr->getConnector(); $this->assertNotNull($connector); $config = $this->getServiceManager()->get('VuFind\\Config'); $this->assertNotNull($config); $options = new Options($config); $this->assertNotNull($options); $params = new Params($options, $config); $this->assertNotNull($params); $testedFields = array('institution', 'format'); //try each field foreach ($testedFields as $currentField) { $params->addFacet($currentField, $currentField); $paramBag = $params->getBackendParameters(); $this->assertTrue(is_array($paramBag->get('facet'))); $query = new Query("*:*"); $collection = $solr->search($query, 0, 0, $paramBag); $this->assertNotNull($collection); //get all possible filter values of current facet field $facets = $collection->getFacets()->getFieldFacets()->getArrayCopy(); $list = $facets[$currentField]; $list->rewind(); $allFilters = array(); while ($list->valid()) { $allFilters[] = $list->key(); $list->next(); } for ($i = 0; $i < count($allFilters); $i++) { for ($j = $i + 1; $j < count($allFilters); $j++) { //test all possible pairs of filters for current facet field $params = new Params($options, $config); $params->addFacet($currentField, $currentField); $params->setMultiselectFacets(array($currentField)); $params->addFilter($currentField . ':' . $allFilters[$i]); $paramBag = $params->getBackendParameters(); $collection = $solr->search($query, 0, 0, $paramBag); $this->assertNotNull($collection); $total1 = $collection->getTotal(); $params->addFilter($currentField . ':' . $allFilters[$j]); $paramBag = $params->getBackendParameters(); $collection = $solr->search($query, 0, 0, $paramBag); $this->assertNotNull($collection); $this->assertNotNull($collection); $total2 = $collection->getTotal(); if ($total2 > $total1) { //adding multifacet filter caused increasment of records in search results , we're done return; } } } } $this->fail("Multifacets test failed, multifacets has no effect on solr response." . " Tested fields: [ " . implode(", ", $testedFields) . " ]"); }
/** * Figure out which bib IDs to load from the ILS. * * @param \VuFind\ILS\Connection $catalog ILS connection * @param \VuFind\Search\Solr\Params $params Solr parameters * @param string $range Range setting * @param string $dept Department setting * @param \Zend\Mvc\Controller\Plugin\FlashMessenger $flash Flash messenger * * @return array */ public function getBibIDsFromCatalog($catalog, $params, $range, $dept, $flash) { // The code always pulls in enough catalog results to get a fixed number // of pages worth of Solr results. Note that if the Solr index is out of // sync with the ILS, we may see fewer results than expected. $resultPages = $this->getResultPages(); $perPage = $params->getLimit(); $newItems = $catalog->getNewItems(1, $perPage * $resultPages, $range, $dept); // Build a list of unique IDs $bibIDs = []; for ($i = 0; $i < count($newItems['results']); $i++) { $bibIDs[] = $newItems['results'][$i]['id']; } // Truncate the list if it is too long: $limit = $params->getQueryIDLimit(); if (count($bibIDs) > $limit) { $bibIDs = array_slice($bibIDs, 0, $limit); $flash->setNamespace('info')->addMessage('too_many_new_items'); } return $bibIDs; }
/** * Set parameters based on a search object * * @param \Zend\StdLib\Parameters $request Parameter object representing user * request. * * @return void */ public function initFromRequest($request) { parent::initFromRequest($request); // Force custom facet settings: $this->facetConfig = array(); $this->addFacet('authorStr'); $this->setFacetOffset(($this->getPage() - 1) * $this->getLimit()); $this->setFacetLimit($this->getLimit() * 10); // Sorting - defaults to off with unlimited facets, so let's // be explicit here for simplicity. if ($this->getSort() == 'author') { $this->setFacetSort('index'); } else { $this->setFacetSort('count'); } }
/** * Add filters to the object based on values found in the request object. * * @param \Zend\StdLib\Parameters $request Parameter object representing user * request. * * @return void */ protected function initFilters($request) { parent::initFilters($request); $this->initSpatialDateRangeFilter($request); $this->initNewItemsFilter($request); }
/** * Process one instance of a spelling replacement and modify the return * data structure with the details of what was done. * * @param string $term The actually term we're replacing * @param string $targetTerm The term above, or the token it is inside * @param bool $inToken Flag for whether the token or term is used * @param array $details The spelling suggestions * @param array $returnArray Return data structure so far * @param Params $params Params helper object * * @return array $returnArray modified */ protected function doSingleReplace($term, $targetTerm, $inToken, $details, $returnArray, Params $params) { $returnArray[$targetTerm]['freq'] = $details['freq']; foreach ($details['suggestions'] as $word => $freq) { // If the suggested word is part of a token if ($inToken) { // We need to make sure we replace the whole token $replacement = str_replace($term, $word, $targetTerm); } else { $replacement = $word; } // Do we need to show the whole, modified query? if ($this->phrase) { $label = $params->getDisplayQueryWithReplacedTerm($targetTerm, $replacement); } else { $label = $replacement; } // Basic spelling suggestion data $returnArray[$targetTerm]['suggestions'][$label] = ['freq' => $freq, 'new_term' => $replacement]; // Only generate expansions if enabled in config if ($this->expand) { // Parentheses differ for shingles if (strstr($targetTerm, " ") !== false) { $replacement = "(({$targetTerm}) OR ({$replacement}))"; } else { $replacement = "({$targetTerm} OR {$replacement})"; } $returnArray[$targetTerm]['suggestions'][$label]['expand_term'] = $replacement; } } return $returnArray; }
/** * Pull the search parameters * * @param \Zend\StdLib\Parameters $request Parameter object representing user * request. * * @return void */ public function initFromRequest($request) { if (null === $this->collectionID) { throw new \Exception('Collection ID missing'); } if (null === $this->collectionField) { throw new \Exception('Collection field missing'); } parent::initFromRequest($request); // We don't spellcheck this screen; it's not for free user input anyway $options = $this->getOptions(); $options->spellcheckEnabled(false); // Prepare the search $safeId = addcslashes($this->collectionID, '"'); $options->addHiddenFilter($this->collectionField . ':"' . $safeId . '"'); $options->addHiddenFilter('!id:"' . $safeId . '"'); }
/** * Send scheduled alerts for a view. * * @return void */ protected function processViewAlerts() { $this->msg(" Sending scheduled alerts for view: {$this->localDir} " . "(base: {$this->scheduleBaseUrl})"); $iso8601 = 'Y-m-d\\TH:i:s\\Z'; $configLoader = $this->getServiceLocator()->get('VuFind\\Config'); $this->iniReader = new IniReader(); $this->iniReader->setNestSeparator(chr(0)); $hmac = $this->getServiceLocator()->get('VuFind\\HMAC'); $userTable = $this->getTable('User'); $backend = $this->getServiceLocator()->get('VuFind\\Search\\BackendManager')->get('Solr'); $viewManager = $this->getServiceLocator()->get('viewmanager'); $viewModel = $viewManager->getViewModel(); $renderer = $viewManager->getRenderer(); $emailer = $this->getServiceLocator()->get('VuFind\\Mailer'); $translator = $renderer->plugin('translate'); $urlHelper = $renderer->plugin('url'); $todayTime = new \DateTime(); $user = false; $institution = false; $institutionConfigs = false; $scheduled = $this->searchTable->getScheduledSearches($this->scheduleBaseUrl); $this->msg(sprintf(' Processing %d searches', count($scheduled))); foreach ($scheduled as $s) { $lastTime = new \DateTime($s->finna_last_executed); $schedule = $s->finna_schedule; if ($schedule == 1) { // Daily if ($todayTime->format('Y-m-d') == $lastTime->format('Y-m-d')) { $this->msg(' Bypassing search ' . $s->id . ': previous execution too recent (daily, ' . $lastTime->format($iso8601) . ')'); continue; } } else { if ($schedule == 2) { $diff = $todayTime->diff($lastTime); if ($diff->days < 6) { $this->msg(' Bypassing search ' . $s->id . ': previous execution too recent (weekly, ' . $lastTime->format($iso8601) . ')'); continue; } } else { $this->err('Search ' . $s->id . ': unknown schedule: ' . $s->schedule); continue; } } if ($user === false || $s->user_id != $user->id) { if (!($user = $userTable->getById($s->user_id))) { $this->err('Search ' . $s->id . ': user ' . $s->user_id . ' does not exist '); continue; } } if (!$user->email || trim($user->email) == '') { $this->err('User ' . $user->username . ' does not have an email address, bypassing alert ' . $s->id); continue; } $scheduleUrl = parse_url($s->finna_schedule_base_url); if (!isset($scheduleUrl['host'])) { $this->err('Could not resolve institution for search ' . $s->id . ' with schedule_base_url: ' . var_export($scheduleUrl, true)); continue; } // Set email language $language = $this->mainConfig->Site->language; if ($user->finna_language != '' && in_array($user->finna_language, array_keys($this->mainConfig->Languages->toArray()))) { $language = $user->finna_language; } $this->getServiceLocator()->get('VuFind\\Translator')->addTranslationFile('ExtendedIni', null, $this->defaultPath, $language)->setLocale($language); // Prepare query $searchObject = $s->getSearchObject(); $searchService = $this->getServiceLocator()->get('VuFind\\Search'); if ($searchObject->cl != 'Solr') { $this->err('Unsupported search class ' . $s->cl . ' for search ' . $s->id); continue; } $limit = 50; $options = new Options($configLoader); $params = new Params($options, $configLoader); $params->deminify($searchObject); $params->setLimit($limit); $params->setSort('first_indexed+desc'); $query = $params->getQuery(); $searchParams = $params->getBackendParameters(); $searchTime = gmdate($iso8601, time()); try { $collection = $searchService->search('Solr', $query, 0, $limit, $searchParams); $resultsTotal = $collection->getTotal(); if ($resultsTotal < 1) { $this->msg('No results found for search ' . $s->id); continue; } $records = $collection->getRecords(); } catch (\VuFindSearch\Backend\Exception\BackendException $e) { $this->err('Error processing search ' . $s->id . ': ' . $e->getMessage()); } $newestRecordDate = date($iso8601, strtotime($records[0]->getFirstIndexed())); $lastExecutionDate = $lastTime->format($iso8601); if ($newestRecordDate < $lastExecutionDate) { $this->msg('No new results for search ' . $s->id . ": {$newestRecordDate} < {$lastExecutionDate}"); continue; } // Collect records that have been indexed (for the first time) // after previous scheduled alert run $newRecords = []; foreach ($collection->getRecords() as $rec) { $recDate = date($iso8601, strtotime($rec->getFirstIndexed())); if ($recDate < $lastExecutionDate) { break; } $newRecords[] = $rec; } // Prepare email content $viewBaseUrl = $searchUrl = $s->finna_schedule_base_url; $searchUrl .= $urlHelper->__invoke($options->getSearchAction()); $urlQueryHelper = new UrlQueryHelper($params); $searchUrl .= str_replace('&', '&', $urlQueryHelper->getParams()); $secret = $s->getUnsubscribeSecret($hmac, $user); $unsubscribeUrl = $s->finna_schedule_base_url; $unsubscribeUrl .= $urlHelper->__invoke('myresearch-unsubscribe') . "?id={$s->id}&key={$secret}"; $params->setServiceLocator($this->getServiceLocator()); $filters = $this->processFilters($params->getFilterList()); $params = ['records' => $newRecords, 'info' => ['baseUrl' => $viewBaseUrl, 'description' => $params->getDisplayQuery(), 'recordCount' => count($records), 'url' => $searchUrl, 'unsubscribeUrl' => $unsubscribeUrl, 'filters' => $filters]]; $message = $renderer->render('Email/scheduled-alert.phtml', $params); $subject = $this->mainConfig->Site->title . ': ' . $translator->__invoke('Scheduled Alert Results'); $from = $this->mainConfig->Site->email; $to = $user->email; try { $this->getServiceLocator()->get('VuFind\\Mailer')->send($to, $from, $subject, $message); } catch (MailException $e) { $this->err("Failed to send message to {$user->email}: " . $e->getMessage()); continue; } if ($s->setLastExecuted($searchTime) === 0) { $this->msg('Error updating last_executed date for search ' . $s->id); } } }
/** * @override * * @param string $field Facet field name. * * @return string Human-readable description of field. */ public function getFacetLabel($field) { switch ($field) { case 'publishDate': return 'adv_search_year'; default: return parent::getFacetLabel($field); } }