Open Journal Systems  3.3.0
ArticleSearch.inc.php
1 <?php
2 
18 import('lib.pkp.classes.search.SubmissionSearch');
19 
24  public function getSparseArray($unorderedResults, $orderBy, $orderDir, $exclude) {
25  // Calculate a well-ordered (unique) score.
26  $resultCount = count($unorderedResults);
27  $i = 0;
28  foreach ($unorderedResults as $submissionId => &$data) {
29  // Reference is necessary to permit modification
30  $data['score'] = ($resultCount * $data['count']) + $i++;
31  }
32 
33  // If we got a primary sort order then apply it and use score as secondary
34  // order only.
35  // NB: We apply order after merging and before paging/formatting. Applying
36  // order before merging would require us to retrieve dependent objects for
37  // results being purged later. Doing everything in a closed SQL is not
38  // possible (e.g. for authors). Applying sort order after paging and
39  // formatting is not possible as we have to order the whole list before
40  // slicing it. So this seems to be the most appropriate place, although we
41  // may have to retrieve some objects again when formatting results.
42  $orderedResults = array();
43  $authorDao = DAORegistry::getDAO('AuthorDAO'); /* @var $authorDao AuthorDAO */
44  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
45  $contextDao = Application::getContextDAO();
46  $contextTitles = array();
47  if ($orderBy == 'popularityAll' || $orderBy == 'popularityMonth') {
49  $metricType = $application->getDefaultMetricType();
50  if (is_null($metricType)) {
51  // If no default metric has been found then sort by score...
52  $orderBy = 'score';
53  } else {
54  // Retrieve a metrics report for all submissions.
55  $column = STATISTICS_DIMENSION_SUBMISSION_ID;
56  $filter = array(
57  STATISTICS_DIMENSION_ASSOC_TYPE => array(ASSOC_TYPE_GALLEY, ASSOC_TYPE_SUBMISSION),
58  STATISTICS_DIMENSION_SUBMISSION_ID => array(array_keys($unorderedResults))
59  );
60  if ($orderBy == 'popularityMonth') {
61  $oneMonthAgo = date('Ymd', strtotime('-1 month'));
62  $today = date('Ymd');
63  $filter[STATISTICS_DIMENSION_DAY] = array('from' => $oneMonthAgo, 'to' => $today);
64  }
65  $rawReport = $application->getMetrics($metricType, $column, $filter);
66  foreach ($rawReport as $row) {
67  $unorderedResults[$row['submission_id']]['metric'] = (int)$row['metric'];
68  }
69  }
70  }
71 
72  $i=0; // Used to prevent ties from clobbering each other
73  foreach ($unorderedResults as $submissionId => $data) {
74  // Exclude unwanted IDs.
75  if (in_array($submissionId, $exclude)) continue;
76 
77  switch ($orderBy) {
78  case 'authors':
79  $submission = $submissionDao->getById($submissionId);
80  $orderKey = $submission->getAuthorString();
81  break;
82 
83  case 'title':
84  $submission = $submissionDao->getById($submissionId);
85  $orderKey = '';
86  if (!empty($submission->getCurrentPublication())) {
87  $orderKey = $submission->getCurrentPublication()->getLocalizedData('title');
88  }
89  break;
90 
91  case 'journalTitle':
92  if (!isset($contextTitles[$data['journal_id']])) {
93  $context = $contextDao->getById($data['journal_id']);
94  $contextTitles[$data['journal_id']] = $context->getLocalizedName();
95  }
96  $orderKey = $contextTitles[$data['journal_id']];
97  break;
98 
99  case 'issuePublicationDate':
100  case 'publicationDate':
101  $orderKey = $data[$orderBy];
102  break;
103 
104  case 'popularityAll':
105  case 'popularityMonth':
106  $orderKey = (isset($data['metric']) ? $data['metric'] : 0);
107  break;
108 
109  default: // order by score.
110  $orderKey = $data['score'];
111  }
112  if (!isset($orderedResults[$orderKey])) {
113  $orderedResults[$orderKey] = array();
114  }
115  $orderedResults[$orderKey][$data['score'] + $i++] = $submissionId;
116  }
117 
118  // Order the results by primary order.
119  if (strtolower($orderDir) == 'asc') {
120  ksort($orderedResults);
121  } else {
122  krsort($orderedResults);
123  }
124 
125  // Order the result by secondary order and flatten it.
126  $finalOrder = array();
127  foreach($orderedResults as $orderKey => $submissionIds) {
128  if (count($submissionIds) == 1) {
129  $finalOrder[] = array_pop($submissionIds);
130  } else {
131  if (strtolower($orderDir) == 'asc') {
132  ksort($submissionIds);
133  } else {
134  krsort($submissionIds);
135  }
136  $finalOrder = array_merge($finalOrder, array_values($submissionIds));
137  }
138  }
139  return $finalOrder;
140  }
141 
147  public function getSearchFilters($request) {
148  $searchFilters = array(
149  'query' => $request->getUserVar('query'),
150  'searchJournal' => $request->getUserVar('searchJournal'),
151  'abstract' => $request->getUserVar('abstract'),
152  'authors' => $request->getUserVar('authors'),
153  'title' => $request->getUserVar('title'),
154  'galleyFullText' => $request->getUserVar('galleyFullText'),
155  'discipline' => $request->getUserVar('discipline'),
156  'subject' => $request->getUserVar('subject'),
157  'type' => $request->getUserVar('type'),
158  'coverage' => $request->getUserVar('coverage'),
159  'indexTerms' => $request->getUserVar('indexTerms')
160  );
161 
162  // Is this a simplified query from the navigation
163  // block plugin?
164  $simpleQuery = $request->getUserVar('simpleQuery');
165  if (!empty($simpleQuery)) {
166  // In the case of a simplified query we get the
167  // filter type from a drop-down.
168  $searchType = $request->getUserVar('searchField');
169  if (array_key_exists($searchType, $searchFilters)) {
170  $searchFilters[$searchType] = $simpleQuery;
171  }
172  }
173 
174  // Publishing dates.
175  $fromDate = $request->getUserDateVar('dateFrom', 1, 1);
176  $searchFilters['fromDate'] = (is_null($fromDate) ? null : date('Y-m-d H:i:s', $fromDate));
177  $toDate = $request->getUserDateVar('dateTo', 32, 12, null, 23, 59, 59);
178  $searchFilters['toDate'] = (is_null($toDate) ? null : date('Y-m-d H:i:s', $toDate));
179 
180  // Instantiate the context.
181  $context = $request->getContext();
182  $siteSearch = !((boolean)$context);
183  if ($siteSearch) {
184  $contextDao = Application::getContextDAO();
185  if (!empty($searchFilters['searchJournal'])) {
186  $context = $contextDao->getById($searchFilters['searchJournal']);
187  } elseif (array_key_exists('journalTitle', $request->getUserVars())) {
188  $contexts = $contextDao->getAll(true);
189  while ($context = $contexts->next()) {
190  if (in_array(
191  $request->getUserVar('journalTitle'),
192  (array) $context->getTitle(null)
193  )) break;
194  }
195  }
196  }
197  $searchFilters['searchJournal'] = $context;
198  $searchFilters['siteSearch'] = $siteSearch;
199 
200  return $searchFilters;
201  }
202 
209  public function getKeywordsFromSearchFilters($searchFilters) {
210  $indexFieldMap = $this->getIndexFieldMap();
211  $indexFieldMap[SUBMISSION_SEARCH_INDEX_TERMS] = 'indexTerms';
212  $keywords = array();
213  if (isset($searchFilters['query'])) {
214  $keywords[null] = $searchFilters['query'];
215  }
216  foreach($indexFieldMap as $bitmap => $searchField) {
217  if (isset($searchFilters[$searchField]) && !empty($searchFilters[$searchField])) {
218  $keywords[$bitmap] = $searchFilters[$searchField];
219  }
220  }
221  return $keywords;
222  }
223 
232  public function formatResults($results, $user = null) {
233  $issueDao = DAORegistry::getDAO('IssueDAO'); /* @var $issueDao IssueDAO */
234  $contextDao = Application::getContextDAO();
235  $sectionDao = DAORegistry::getDAO('SectionDAO'); /* @var $sectionDao SectionDAO */
236 
237  $publishedSubmissionCache = array();
238  $articleCache = array();
239  $issueCache = array();
240  $issueAvailabilityCache = array();
241  $contextCache = array();
242  $sectionCache = array();
243 
244  $returner = array();
245  foreach ($results as $articleId) {
246  // Get the article, storing in cache if necessary.
247  if (!isset($articleCache[$articleId])) {
248  $submission = Services::get('submission')->get($articleId);
249  $publishedSubmissionCache[$articleId] = $submission;
250  $articleCache[$articleId] = $submission;
251  }
252  $article = $articleCache[$articleId];
253  $publishedSubmission = $publishedSubmissionCache[$articleId];
254 
255  if ($publishedSubmission && $article) {
256  $sectionId = $article->getSectionId();
257  if (!isset($sectionCache[$sectionId])) {
258  $sectionCache[$sectionId] = $sectionDao->getById($sectionId);
259  }
260 
261  // Get the context, storing in cache if necessary.
262  $contextId = $article->getData('contextId');
263  if (!isset($contextCache[$contextId])) {
264  $contextCache[$contextId] = $contextDao->getById($contextId);
265  }
266 
267  // Get the issue, storing in cache if necessary.
268  $issueId = $publishedSubmission->getCurrentPublication()->getData('issueId');
269  if (!isset($issueCache[$issueId])) {
270  $issue = $issueDao->getById($issueId);
271  $issueCache[$issueId] = $issue;
272  import('classes.issue.IssueAction');
273  $issueAction = new IssueAction();
274  $issueAvailabilityCache[$issueId] = !$issueAction->subscriptionRequired($issue, $contextCache[$contextId]) || $issueAction->subscribedUser($user, $contextCache[$contextId], $issueId, $articleId) || $issueAction->subscribedDomain(Application::get()->getRequest(), $contextCache[$contextId], $issueId, $articleId);
275  }
276 
277  // Only display articles from published issues.
278  if (!isset($issueCache[$issueId]) || !$issueCache[$issueId]->getPublished()) continue;
279 
280  // Store the retrieved objects in the result array.
281  $returner[] = array(
282  'article' => $article,
283  'publishedSubmission' => $publishedSubmissionCache[$articleId],
284  'issue' => $issueCache[$issueId],
285  'journal' => $contextCache[$contextId],
286  'issueAvailable' => $issueAvailabilityCache[$issueId],
287  'section' => $sectionCache[$sectionId]
288  );
289  }
290  }
291  return $returner;
292  }
293 
300  public function getSimilarityTerms($submissionId) {
301  // Check whether a search plugin provides terms for a similarity search.
302  $searchTerms = array();
303  $result = HookRegistry::call('ArticleSearch::getSimilarityTerms', array($submissionId, &$searchTerms));
304 
305  // If no plugin implements the hook then use the subject keywords
306  // of the submission for a similarity search.
307  if ($result === false) {
308  // Retrieve the article.
309  $article = Services::get('submission')->get($submissionId);
310  if ($article->getData('status') === STATUS_PUBLISHED) {
311  // Retrieve keywords (if any).
312  $submissionSubjectDao = DAORegistry::getDAO('SubmissionKeywordDAO'); /* @var $submissionSubjectDao SubmissionKeywordDAO */
313  $allSearchTerms = array_filter($submissionSubjectDao->getKeywords($article->getId(), array(AppLocale::getLocale(), $article->getLocale(), AppLocale::getPrimaryLocale())));
314  foreach ($allSearchTerms as $locale => $localeSearchTerms) {
315  $searchTerms += $localeSearchTerms;
316  }
317  }
318  }
319 
320  return $searchTerms;
321  }
322 
323  public function getIndexFieldMap() {
324  return array(
325  SUBMISSION_SEARCH_AUTHOR => 'authors',
326  SUBMISSION_SEARCH_TITLE => 'title',
327  SUBMISSION_SEARCH_ABSTRACT => 'abstract',
328  SUBMISSION_SEARCH_GALLEY_FILE => 'galleyFullText',
329  SUBMISSION_SEARCH_DISCIPLINE => 'discipline',
330  SUBMISSION_SEARCH_SUBJECT => 'subject',
331  SUBMISSION_SEARCH_TYPE => 'type',
332  SUBMISSION_SEARCH_COVERAGE => 'coverage'
333  );
334  }
335 
339  public function getResultSetOrderingOptions($request) {
340  $resultSetOrderingOptions = array(
341  'score' => __('search.results.orderBy.relevance'),
342  'authors' => __('search.results.orderBy.author'),
343  'issuePublicationDate' => __('search.results.orderBy.issue'),
344  'publicationDate' => __('search.results.orderBy.date'),
345  'title' => __('search.results.orderBy.article')
346  );
347 
348  // Only show the "popularity" options if we have a default metric.
350  $metricType = $application->getDefaultMetricType();
351  if (!is_null($metricType)) {
352  $resultSetOrderingOptions['popularityAll'] = __('search.results.orderBy.popularityAll');
353  $resultSetOrderingOptions['popularityMonth'] = __('search.results.orderBy.popularityMonth');
354  }
355 
356  // Only show the "journal title" option if we have several journals.
357  $context = $request->getContext();
358  if (!$context) {
359  $resultSetOrderingOptions['journalTitle'] = __('search.results.orderBy.journal');
360  }
361 
362  // Let plugins mangle the search ordering options.
364  'SubmissionSearch::getResultSetOrderingOptions',
365  array($context, &$resultSetOrderingOptions)
366  );
367 
368  return $resultSetOrderingOptions;
369  }
370 
374  public function getDefaultOrderDir($orderBy) {
375  $orderDir = 'asc';
376  if (in_array($orderBy, array('score', 'publicationDate', 'issuePublicationDate', 'popularityAll', 'popularityMonth'))) {
377  $orderDir = 'desc';
378  }
379  return $orderDir;
380  }
381 
385  protected function getSearchDao() {
386  return DAORegistry::getDAO('ArticleSearchDAO');
387  }
388 }
389 
390 
ArticleSearch\formatResults
formatResults($results, $user=null)
Definition: ArticleSearch.inc.php:232
ArticleSearch\getKeywordsFromSearchFilters
getKeywordsFromSearchFilters($searchFilters)
Definition: ArticleSearch.inc.php:209
ArticleSearch\getDefaultOrderDir
getDefaultOrderDir($orderBy)
Definition: ArticleSearch.inc.php:374
Application\getContextDAO
static getContextDAO()
Definition: Application.inc.php:137
ArticleSearch\getSimilarityTerms
getSimilarityTerms($submissionId)
Definition: ArticleSearch.inc.php:300
SubmissionSearch
Class for retrieving search results.
Definition: SubmissionSearch.inc.php:35
$application
$application
Definition: index.php:65
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
AppLocale\getPrimaryLocale
static getPrimaryLocale()
Definition: env1/MockAppLocale.inc.php:95
ArticleSearch\getIndexFieldMap
getIndexFieldMap()
Definition: ArticleSearch.inc.php:323
IssueAction
IssueAction class.
Definition: IssueAction.inc.php:17
ArticleSearch\getSearchDao
getSearchDao()
Definition: ArticleSearch.inc.php:385
ArticleSearch\getResultSetOrderingOptions
getResultSetOrderingOptions($request)
Definition: ArticleSearch.inc.php:339
ArticleSearch\getSearchFilters
getSearchFilters($request)
Definition: ArticleSearch.inc.php:147
ArticleSearch\getSparseArray
getSparseArray($unorderedResults, $orderBy, $orderDir, $exclude)
Definition: ArticleSearch.inc.php:24
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
ArticleSearch
Class for retrieving article search results.
Definition: ArticleSearch.inc.php:20
HookRegistry\call
static call($hookName, $args=null)
Definition: HookRegistry.inc.php:86
AppLocale\getLocale
static getLocale()
Definition: env1/MockAppLocale.inc.php:40
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49