Open Journal Systems  3.3.0
PKPSubmissionQueryBuilder.inc.php
1 <?php
2 
17 
18 use Illuminate\Database\Capsule\Manager as Capsule;
20 
22 
24  protected $categoryIds = null;
25 
27  protected $contextId = null;
28 
30  protected $columns = array();
31 
33  protected $orderColumn = 's.date_submitted';
34 
36  protected $orderDirection = 'DESC';
37 
39  protected $statuses = null;
40 
42  protected $stageIds = null;
43 
45  protected $assignedTo = [];
46 
48  protected $searchPhrase = null;
49 
51  protected $isIncomplete = false;
52 
54  protected $isOverdue = false;
55 
57  protected $daysInactive = null;
58 
60  protected $limit = null;
61 
63  protected $offset = 0;
64 
72  public function filterByContext($contextId) {
73  $this->contextId = $contextId;
74  return $this;
75  }
76 
85  public function orderBy($column, $direction = 'DESC') {
86  // Bring in orderby constants
87  import('classes.submission.SubmissionDAO');
88  if ($column === 'lastModified') {
89  $this->orderColumn = 's.last_modified';
90  } elseif ($column === 'dateLastActivity') {
91  $this->orderColumn = 's.date_last_activity';
92  } elseif ($column === 'title') {
93  $this->orderColumn = Capsule::raw('COALESCE(publication_tlps.setting_value, publication_tlpsl.setting_value)');
94  } elseif ($column === 'seq') {
95  $this->orderColumn = 'po.seq';
96  } elseif ($column === ORDERBY_DATE_PUBLISHED) {
97  $this->orderColumn = 'po.date_published';
98  } else {
99  $this->orderColumn = 's.date_submitted';
100  }
101  $this->orderDirection = $direction;
102  return $this;
103  }
104 
112  public function filterByCategories($categoryIds) {
113  if (!is_null($categoryIds) && !is_array($categoryIds)) {
115  }
116  $this->categoryIds = $categoryIds;
117  return $this;
118  }
119 
127  public function filterByStatus($statuses) {
128  if (!is_null($statuses) && !is_array($statuses)) {
129  $statuses = array($statuses);
130  }
131  $this->statuses = $statuses;
132  return $this;
133  }
134 
142  public function filterByStageIds($stageIds) {
143  if (!is_null($stageIds) && !is_array($stageIds)) {
144  $stageIds = array($stageIds);
145  }
146  $this->stageIds = $stageIds;
147  return $this;
148  }
149 
157  public function filterByIncomplete($isIncomplete) {
158  $this->isIncomplete = $isIncomplete;
159  return $this;
160  }
161 
169  public function filterByOverdue($isOverdue) {
170  $this->isOverdue = $isOverdue;
171  return $this;
172  }
173 
181  public function filterByDaysInactive($daysInactive) {
182  $this->daysInactive = $daysInactive;
183  return $this;
184  }
185 
194  public function assignedTo($assignedTo) {
195  $this->assignedTo = $assignedTo;
196  return $this;
197  }
198 
206  public function searchPhrase($phrase) {
207  $this->searchPhrase = $phrase;
208  return $this;
209  }
210 
218  public function limitTo($count) {
219  $this->limit = $count;
220  return $this;
221  }
222 
230  public function offsetBy($offset) {
231  $this->offset = $offset;
232  return $this;
233  }
234 
238  public function getCount() {
239  return $this
240  ->getQuery()
241  ->select('s.submission_id')
242  ->get()
243  ->count();
244  }
245 
249  public function getIds() {
250  return $this
251  ->getQuery()
252  ->select('s.submission_id')
253  ->pluck('s.submission_id')
254  ->toArray();
255  }
256 
260  public function getQuery() {
261  $this->columns[] = 's.*';
262  $q = Capsule::table('submissions as s')
263  ->orderBy($this->orderColumn, $this->orderDirection)
264  ->groupBy('s.submission_id');
265 
266  // context
267  // Never permit a query without a context_id clause unless the '*' wildcard
268  // has been set explicitely.
269  if (is_null($this->contextId)) {
270  $q->where('s.context_id', '=', CONTEXT_ID_NONE);
271  } elseif ($this->contextId !== '*') {
272  $q->where('s.context_id', '=' , $this->contextId);
273  }
274 
275  // order by title
276  if (is_object($this->orderColumn) && $this->orderColumn->getValue() === 'COALESCE(publication_tlps.setting_value, publication_tlpsl.setting_value)') {
277  $locale = \AppLocale::getLocale();
278  $this->columns[] = Capsule::raw('COALESCE(publication_tlps.setting_value, publication_tlpsl.setting_value)');
279  $q->leftJoin('publications as publication_tlp', 's.current_publication_id', '=', 'publication_tlp.publication_id')
280  ->leftJoin('publication_settings as publication_tlps', 'publication_tlp.publication_id', '=', 'publication_tlps.publication_id')
281  ->where('publication_tlps.setting_name', '=', 'title')
282  ->where('publication_tlps.locale', '=', $locale);
283  $q->leftJoin('publications as publication_tlpl', 's.current_publication_id', '=', 'publication_tlpl.publication_id')
284  ->leftJoin('publication_settings as publication_tlpsl', 'publication_tlp.publication_id', '=', 'publication_tlpsl.publication_id')
285  ->where('publication_tlpsl.setting_name', '=', 'title')
286  ->where('publication_tlpsl.locale', '=', Capsule::raw('publication_tlpl.locale'));
287  $q->groupBy(Capsule::raw('COALESCE(publication_tlps.setting_value, publication_tlpsl.setting_value)'));
288  }
289 
290  // order by publication sequence
291  if ($this->orderColumn === 'po.seq') {
292  $this->columns[] = 'po.seq';
293  $q->leftJoin('publications as po', 's.current_publication_id', '=', 'po.publication_id');
294  $q->groupBy('po.seq');
295 
296  // order by date of current version's publication
297  } else if ($this->orderColumn === 'po.date_published') {
298  $this->columns[] = 'po.date_published';
299  $q->leftJoin('publications as po', 's.current_publication_id', '=', 'po.publication_id');
300  }
301 
302  // statuses
303  if (!is_null($this->statuses)) {
304  $q->whereIn('s.status', $this->statuses);
305  }
306 
307  // stage ids
308  if (!is_null($this->stageIds)) {
309  $q->whereIn('s.stage_id', $this->stageIds);
310  }
311 
312  // incomplete submissions
313  if ($this->isIncomplete) {
314  $q->where('s.submission_progress', '>', 0);
315  }
316 
317  //inactive for X days
318  if ($this->daysInactive) {
319  $q->where('s.date_last_activity', '<', \Core::getCurrentDate(strtotime('-'.$this->daysInactive.' days')));
320  }
321 
322  // overdue submissions
323  if ($this->isOverdue) {
324  $q->leftJoin('review_assignments as raod', 'raod.submission_id', '=', 's.submission_id')
325  ->leftJoin('review_rounds as rr', function($table) {
326  $table->on('rr.submission_id', '=', 's.submission_id');
327  $table->on('raod.review_round_id', '=', 'rr.review_round_id');
328  });
329  // Only get overdue assignments on active review rounds
330  import('lib.pkp.classes.submission.reviewRound.ReviewRound');
331  $q->where('rr.status', '!=', REVIEW_ROUND_STATUS_RESUBMIT_FOR_REVIEW);
332  $q->where('rr.status', '!=', REVIEW_ROUND_STATUS_SENT_TO_EXTERNAL);
333  $q->where('rr.status', '!=', REVIEW_ROUND_STATUS_ACCEPTED);
334  $q->where('rr.status', '!=', REVIEW_ROUND_STATUS_DECLINED);
335  $q->where(function ($q) {
336  $q->where('raod.declined', '<>', 1);
337  $q->where('raod.cancelled', '<>', 1);
338  $q->where(function ($q) {
339  $q->where('raod.date_due', '<', \Core::getCurrentDate(strtotime('tomorrow')));
340  $q->whereNull('raod.date_completed');
341  });
342  $q->orWhere(function ($q) {
343  $q->where('raod.date_response_due', '<', \Core::getCurrentDate(strtotime('tomorrow')));
344  $q->whereNull('raod.date_confirmed');
345  });
346  });
347  }
348 
349  // Assigned to
350  $isAssignedOnly = !empty($this->assignedTo) && $this->assignedTo !== -1;
351  if ($isAssignedOnly) {
353 
354  // Stage assignments
355  $q->leftJoin('stage_assignments as sa', function($table) use ($assignedTo) {
356  $table->on('s.submission_id', '=', 'sa.submission_id');
357  $table->whereIn('sa.user_id', $assignedTo);
358  });
359 
360  // Review assignments
361  $q->leftJoin('review_assignments as ra', function($table) use ($assignedTo) {
362  $table->on('s.submission_id', '=', 'ra.submission_id');
363  $table->on('ra.declined', '=', Capsule::raw((int) 0));
364  $table->whereIn('ra.reviewer_id', $assignedTo);
365  });
366 
367  $q->where(function($q) {
368  $q->whereNotNull('sa.stage_assignment_id');
369  $q->orWhereNotNull('ra.review_id');
370  });
371  } elseif ($this->assignedTo === -1) {
372  $sub = Capsule::table('stage_assignments')
373  ->select(Capsule::raw('count(stage_assignments.stage_assignment_id)'))
374  ->leftJoin('user_groups','stage_assignments.user_group_id','=','user_groups.user_group_id')
375  ->where('stage_assignments.submission_id', '=', Capsule::raw('s.submission_id'))
376  ->whereIn('user_groups.role_id', array(ROLE_ID_MANAGER, ROLE_ID_SUB_EDITOR));
377 
378  $q->whereNotNull('s.date_submitted')
379  ->mergeBindings($sub)
380  ->where(Capsule::raw('(' . $sub->toSql() . ')'),'=','0')
381  ->groupBy('s.date_submitted'); // postgres compatibility
382  }
383 
384  // search phrase
385  if (!empty($this->searchPhrase)) {
386  $words = explode(' ', $this->searchPhrase);
387  if (count($words)) {
388  $q->leftJoin('publications as p', 'p.submission_id', '=', 's.submission_id')
389  ->leftJoin('publication_settings as ps','p.publication_id','=','ps.publication_id')
390  ->leftJoin('authors as au','p.publication_id','=','au.publication_id')
391  ->leftJoin('author_settings as aus', 'aus.author_id', '=', 'au.author_id');
392 
393  foreach ($words as $word) {
394  $word = strtolower(addcslashes($word, '%_'));
395  $q->where(function($q) use ($word, $isAssignedOnly) {
396  $q->where(function($q) use ($word) {
397  $q->where('ps.setting_name', 'title');
398  $q->where(Capsule::raw('lower(ps.setting_value)'), 'LIKE', "%{$word}%");
399  })
400  ->orWhere(function($q) use ($word) {
401  $q->where('aus.setting_name', IDENTITY_SETTING_GIVENNAME);
402  $q->where(Capsule::raw('lower(aus.setting_value)'), 'LIKE', "%{$word}%");
403  })
404  ->orWhere(function($q) use ($word, $isAssignedOnly) {
405  $q->where('aus.setting_name', IDENTITY_SETTING_FAMILYNAME);
406  $q->where(Capsule::raw('lower(aus.setting_value)'), 'LIKE', "%{$word}%");
407  })
408  ->orWhere(function($q) use ($word, $isAssignedOnly) {
409  $q->where('aus.setting_name', 'orcid');
410  $q->where(Capsule::raw('lower(aus.setting_value)'), '=', "{$word}");
411  });
412  // Prevent reviewers from matching searches by author name
413  if ($isAssignedOnly) {
414  $q->whereNull('ra.reviewer_id');
415  }
416  if (ctype_digit((string) $word)) {
417  $q->orWhere('s.submission_id', '=', $word);
418  }
419  });
420  }
421 
422  }
423  }
424 
425  // Category IDs
426  if (!empty($this->categoryIds)) {
427  $q->leftJoin('publication_categories as pc', 's.current_publication_id', '=', 'pc.publication_id')
428  ->whereIn('pc.category_id', $this->categoryIds);
429  }
430 
431  // Limit and offset results for pagination
432  if (!is_null($this->limit)) {
433  $q->limit($this->limit);
434  }
435  if (!empty($this->offset)) {
436  $q->offset($this->offset);
437  }
438 
439  // Add app-specific query statements
440  \HookRegistry::call('Submission::getMany::queryObject', array(&$q, $this));
441 
442  $q->select($this->columns);
443 
444  return $q;
445  }
446 
453  abstract function appGet($q);
454 }
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$searchPhrase
$searchPhrase
Definition: PKPSubmissionQueryBuilder.inc.php:75
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\getIds
getIds()
Definition: PKPSubmissionQueryBuilder.inc.php:291
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\searchPhrase
searchPhrase($phrase)
Definition: PKPSubmissionQueryBuilder.inc.php:248
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$categoryIds
$categoryIds
Definition: PKPSubmissionQueryBuilder.inc.php:27
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\filterByIncomplete
filterByIncomplete($isIncomplete)
Definition: PKPSubmissionQueryBuilder.inc.php:199
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$daysInactive
$daysInactive
Definition: PKPSubmissionQueryBuilder.inc.php:93
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\orderBy
orderBy($column, $direction='DESC')
Definition: PKPSubmissionQueryBuilder.inc.php:127
PKP\Services\QueryBuilders
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\filterByOverdue
filterByOverdue($isOverdue)
Definition: PKPSubmissionQueryBuilder.inc.php:211
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\appGet
appGet($q)
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$limit
$limit
Definition: PKPSubmissionQueryBuilder.inc.php:99
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$assignedTo
$assignedTo
Definition: PKPSubmissionQueryBuilder.inc.php:69
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder
Definition: PKPSubmissionQueryBuilder.inc.php:21
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\filterByCategories
filterByCategories($categoryIds)
Definition: PKPSubmissionQueryBuilder.inc.php:154
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\filterByDaysInactive
filterByDaysInactive($daysInactive)
Definition: PKPSubmissionQueryBuilder.inc.php:223
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\limitTo
limitTo($count)
Definition: PKPSubmissionQueryBuilder.inc.php:260
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$offset
$offset
Definition: PKPSubmissionQueryBuilder.inc.php:105
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$isOverdue
$isOverdue
Definition: PKPSubmissionQueryBuilder.inc.php:87
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\offsetBy
offsetBy($offset)
Definition: PKPSubmissionQueryBuilder.inc.php:272
Seboettg\Collection\count
count()
Definition: ArrayListTrait.php:253
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\filterByStatus
filterByStatus($statuses)
Definition: PKPSubmissionQueryBuilder.inc.php:169
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$contextId
$contextId
Definition: PKPSubmissionQueryBuilder.inc.php:33
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\filterByContext
filterByContext($contextId)
Definition: PKPSubmissionQueryBuilder.inc.php:114
Core\getCurrentDate
static getCurrentDate($ts=null)
Definition: Core.inc.php:63
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$stageIds
$stageIds
Definition: PKPSubmissionQueryBuilder.inc.php:63
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$orderDirection
$orderDirection
Definition: PKPSubmissionQueryBuilder.inc.php:51
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\getQuery
getQuery()
Definition: PKPSubmissionQueryBuilder.inc.php:302
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\filterByStageIds
filterByStageIds($stageIds)
Definition: PKPSubmissionQueryBuilder.inc.php:184
HookRegistry\call
static call($hookName, $args=null)
Definition: HookRegistry.inc.php:86
AppLocale\getLocale
static getLocale()
Definition: env1/MockAppLocale.inc.php:40
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\assignedTo
assignedTo($assignedTo)
Definition: PKPSubmissionQueryBuilder.inc.php:236
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$isIncomplete
$isIncomplete
Definition: PKPSubmissionQueryBuilder.inc.php:81
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$orderColumn
$orderColumn
Definition: PKPSubmissionQueryBuilder.inc.php:45
PKP\Services\QueryBuilders\Interfaces\EntityQueryBuilderInterface
Definition: EntityQueryBuilderInterface.inc.php:19
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\getCount
getCount()
Definition: PKPSubmissionQueryBuilder.inc.php:280
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$statuses
$statuses
Definition: PKPSubmissionQueryBuilder.inc.php:57
PKP\Services\QueryBuilders\PKPSubmissionQueryBuilder\$columns
$columns
Definition: PKPSubmissionQueryBuilder.inc.php:39