Skip to content

Commit edc8132

Browse files
committed
#11885 Refactor editTaskTemplate requests and search scope
1 parent 297ef88 commit edc8132

File tree

5 files changed

+116
-77
lines changed

5 files changed

+116
-77
lines changed

api/v1/editTaskTemplates/PKPEditTaskTemplateController.php

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -200,21 +200,9 @@ public function update(UpdateTaskTemplate $request): JsonResponse
200200
$data = $request->validated();
201201

202202
DB::transaction(function () use ($template, $data) {
203-
$userGroupIds = Arr::pull($data, 'userGroupIds');
204-
$updates = collect($data)
205-
->only(['stageId', 'title', 'include', 'type', 'description', 'dueInterval'])
206-
->mapWithKeys(function ($v, $k) {
207-
return match ($k) {
208-
'stageId' => ['stageId' => (int) $v],
209-
'include' => ['include' => (bool) $v],
210-
'type' => ['type' => (int) $v],
211-
'dueInterval' => ['dueInterval' => $v],
212-
default => [$k => $v], // 'title', 'description'
213-
};
214-
})
215-
->all();
216-
217-
$template->update($updates);
203+
$userGroupIds = \Illuminate\Support\Arr::pull($data, 'userGroupIds');
204+
205+
$template->update($data);
218206

219207
if ($userGroupIds !== null) {
220208
$template->userGroups()->sync($userGroupIds);

api/v1/editTaskTemplates/formRequests/AddTaskTemplate.php

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,19 @@
1515

1616
namespace PKP\API\v1\editTaskTemplates\formRequests;
1717

18-
use APP\core\Application;
1918
use Illuminate\Foundation\Http\FormRequest;
2019
use Illuminate\Validation\Rule;
2120
use PKP\editorialTask\enums\EditorialTaskDueInterval;
2221
use PKP\editorialTask\enums\EditorialTaskType;
2322

2423
class AddTaskTemplate extends FormRequest
2524
{
26-
public function authorize(): bool
27-
{
28-
return true;
29-
}
25+
use TaskTemplateRequestTrait;
3026

3127
public function rules(): array
3228
{
33-
$contextId = Application::get()->getRequest()->getContext()->getId();
34-
35-
// build a list of allowed stage IDs from values
36-
$stages = Application::getApplicationStages();
37-
$stageIds = array_values(array_unique(array_map('intval', array_values((array) $stages))));
38-
29+
$contextId = $this->getContextId();
30+
$stageIds = $this->getStageIds();
3931

4032
return [
4133
'type' => ['required', Rule::in(array_column(EditorialTaskType::cases(), 'value'))],
@@ -45,12 +37,7 @@ public function rules(): array
4537
'dueInterval' => ['sometimes', 'nullable', 'string', Rule::in(array_column(EditorialTaskDueInterval::cases(), 'value'))],
4638
'description' => ['sometimes', 'nullable', 'string'],
4739
'userGroupIds' => ['required', 'array', 'min:1'],
48-
'userGroupIds.*' => [
49-
'integer',
50-
'distinct',
51-
Rule::exists('user_groups', 'user_group_id')
52-
->where(fn ($q) => $q->where('context_id', $contextId)),
53-
],
40+
'userGroupIds.*' => $this->userGroupIdsItemRules($contextId),
5441
];
5542
}
5643

@@ -61,7 +48,7 @@ protected function prepareForValidation(): void
6148
$this->merge([
6249
'include' => filter_var($this->input('include', false), FILTER_VALIDATE_BOOLEAN),
6350
'userGroupIds' => array_values(array_map('intval', (array) $this->input('userGroupIds', []))),
64-
'stageId' => is_null($stageId) ? $stageId : (int) $stageId,
51+
'stageId' => is_null($stageId) ? null : (int) $stageId,
6552
'type' => is_null($type) ? null : (int) $type,
6653
]);
6754
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/**
4+
* @file api/v1/editTaskTemplates/formRequests/TaskTemplateRequestTrait.php
5+
*
6+
* Copyright (c) 2025 Simon Fraser University
7+
* Copyright (c) 2025 John Willinsky
8+
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
9+
*
10+
* @class TaskTemplateRequestTrait
11+
*
12+
* @brief Common helpers for resolving context, stage IDs and user group rules in task template form requests.
13+
*
14+
*/
15+
16+
namespace PKP\API\v1\editTaskTemplates\formRequests;
17+
18+
use APP\core\Application;
19+
use Illuminate\Validation\Rule;
20+
21+
trait TaskTemplateRequestTrait
22+
{
23+
protected function getContextId(): int
24+
{
25+
return Application::get()->getRequest()->getContext()->getId();
26+
}
27+
28+
protected function getStageIds(): array
29+
{
30+
$stages = Application::getApplicationStages();
31+
32+
return array_values(
33+
array_unique(
34+
array_map('intval', array_values((array) $stages))
35+
)
36+
);
37+
}
38+
39+
protected function userGroupIdsItemRules(int $contextId): array
40+
{
41+
return [
42+
'integer',
43+
'distinct',
44+
Rule::exists('user_groups', 'user_group_id')
45+
->where(fn ($q) => $q->where('context_id', $contextId)),
46+
];
47+
}
48+
}

api/v1/editTaskTemplates/formRequests/UpdateTaskTemplate.php

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,23 @@
1010

1111
class UpdateTaskTemplate extends FormRequest
1212
{
13-
public function authorize(): bool
14-
{
15-
return true;
16-
}
13+
use TaskTemplateRequestTrait;
1714

1815
public function rules(): array
1916
{
20-
$contextId = Application::get()->getRequest()->getContext()->getId();
21-
22-
// Build allowed stage IDs (values)
23-
$stages = Application::getApplicationStages();
24-
$stageIds = array_values(array_unique(array_map('intval', array_values((array) $stages))));
17+
$contextId = $this->getContextId();
18+
$stageIds = $this->getStageIds();
2519

2620
return [
27-
// all fields are optional but if present must validate
2821
'stageId' => ['sometimes', 'integer', Rule::in($stageIds)],
2922
'title' => ['sometimes', 'string', 'max:255'],
3023
'include' => ['sometimes', 'boolean'],
3124
'description' => ['sometimes', 'nullable', 'string'],
32-
'dueInterval' => ['sometimes', 'nullable', 'string',
33-
Rule::in(array_column(EditorialTaskDueInterval::cases(), 'value'))
34-
],
25+
'dueInterval' => ['sometimes', 'nullable', 'string', Rule::in(array_column(EditorialTaskDueInterval::cases(), 'value'))],
3526
'type' => ['sometimes', Rule::in(array_column(EditorialTaskType::cases(), 'value'))],
3627

3728
'userGroupIds' => ['sometimes', 'array', 'min:1'],
38-
'userGroupIds.*' => [
39-
'integer',
40-
'distinct',
41-
Rule::exists('user_groups', 'user_group_id')
42-
->where(fn ($q) => $q->where('context_id', $contextId)),
43-
],
29+
'userGroupIds.*' => $this->userGroupIdsItemRules($contextId),
4430
];
4531
}
4632

classes/editorialTask/Template.php

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@
2222
use Illuminate\Database\Eloquent\Casts\Attribute;
2323
use Illuminate\Database\Eloquent\Model;
2424
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
25+
use Illuminate\Support\Facades\DB;
2526
use PKP\core\PKPApplication;
2627
use PKP\core\traits\ModelWithSettings;
2728
use PKP\editorialTask\EditorialTask as Task;
2829
use PKP\stageAssignment\StageAssignment;
2930
use PKP\userGroup\UserGroup;
30-
use Illuminate\Support\Facades\DB;
31+
use PKP\editorialTask\enums\EditorialTaskType;
3132

3233
class Template extends Model
3334
{
@@ -189,9 +190,10 @@ public function scopeFilterByTitleLike(Builder $query, string $title): Builder
189190
}
190191

191192
/**
192-
* free-text/ words search across:
193-
* title column
194-
* name, description
193+
* Free-text / words search across:
194+
* - title column
195+
* - name, description (settings)
196+
* Also supports "task" / "discussion" keyword to constrain by type.
195197
*/
196198
public function scopeFilterBySearch(Builder $query, string $phrase): Builder
197199
{
@@ -206,28 +208,56 @@ public function scopeFilterBySearch(Builder $query, string $phrase): Builder
206208
return $query;
207209
}
208210

209-
$settingsTable = $this->getSettingsTable();
210-
$pk = $this->getKeyName();
211-
$selfTable = $this->getTable();
212-
213-
return $query->where(function (Builder $outer) use ($tokens, $settingsTable, $pk, $selfTable) {
214-
foreach ($tokens as $tok) {
215-
// escape % and _
216-
$like = '%' . str_replace(['%', '_'], ['\\%', '\\_'], mb_strtolower($tok, 'UTF-8')) . '%';
217-
218-
$outer->where(function (Builder $q) use ($like, $settingsTable, $pk, $selfTable) {
219-
$q->whereRaw('LOWER(title) LIKE ?', [$like])
220-
->orWhereRaw('LOWER(description) LIKE ?', [$like])
221-
->orWhereExists(function ($sub) use ($like, $settingsTable, $pk, $selfTable) {
222-
$sub->select(DB::raw(1))
223-
->from($settingsTable . ' as ets')
224-
->whereColumn("ets.$pk", "$selfTable.$pk")
225-
->whereIn('ets.setting_name', ['name', 'description'])
226-
->whereRaw('LOWER(ets.setting_value) LIKE ?', [$like]);
227-
});
228-
});
211+
// map special keywords to type values
212+
$typeMap = [
213+
'task' => EditorialTaskType::TASK->value,
214+
'tasks' => EditorialTaskType::TASK->value,
215+
'discussion' => EditorialTaskType::DISCUSSION->value,
216+
'discussions' => EditorialTaskType::DISCUSSION->value,
217+
];
218+
219+
$typeFilter = null;
220+
$keywords = [];
221+
222+
foreach ($tokens as $tok) {
223+
$lower = mb_strtolower($tok, 'UTF-8');
224+
225+
if (isset($typeMap[$lower])) {
226+
$typeFilter = $typeMap[$lower];
227+
continue;
229228
}
230-
});
229+
230+
$keywords[] = $tok;
231+
}
232+
233+
if ($typeFilter !== null) {
234+
$query->filterByType($typeFilter);
235+
}
236+
237+
if ($keywords) {
238+
$settingsTable = $this->getSettingsTable();
239+
$pk = $this->getKeyName();
240+
$selfTable = $this->getTable();
241+
242+
$query->where(function (Builder $outer) use ($keywords, $settingsTable, $pk, $selfTable) {
243+
foreach ($keywords as $tok) {
244+
$like = '%' . str_replace(['%', '_'], ['\\%', '\\_'], mb_strtolower($tok, 'UTF-8')) . '%';
245+
246+
$outer->where(function (Builder $q) use ($like, $settingsTable, $pk, $selfTable) {
247+
$q->whereRaw('LOWER(title) LIKE ?', [$like])
248+
->orWhereRaw('LOWER(description) LIKE ?', [$like])
249+
->orWhereExists(function ($sub) use ($like, $settingsTable, $pk, $selfTable) {
250+
$sub->select(DB::raw(1))
251+
->from($settingsTable . ' as ets')
252+
->whereColumn("ets.$pk", "$selfTable.$pk")
253+
->whereIn('ets.setting_name', ['name', 'description'])
254+
->whereRaw('LOWER(ets.setting_value) LIKE ?', [$like]);
255+
});
256+
});
257+
}
258+
});
259+
}
260+
return $query;
231261
}
232262

233263
}

0 commit comments

Comments
 (0)