PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.0 2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 All 43 releases
← All changes | app/Models/Task.php +45 -3 2.0.0 → 2.2.0 View file →
@@ -6,14 +6,15 @@
6 6 use FluentBoards\App\Services\Helper;
7 7 use FluentBoards\App\Services\TaskService;
8 8 use FluentBoards\Framework\Database\Orm\Builder;
9 9 use FluentBoardsPro\App\Models\TaskAttachment;
10 -use FluentBoardsPro\App\Models\CustomField;
10 +use FluentBoards\App\Models\CustomField;
11 11 use FluentBoardsPro\App\Services\Constant as ProConstant;
12 12 use FluentCrm\App\Models\Subscriber;
13 13
14 14 class Task extends Model
15 15 {
16 +
16 17 protected $table = 'fbs_tasks';
17 18
18 19 protected $guarded = ['id'];
19 20
@@ -99,8 +100,18 @@
99 100 self::adjustSubtaskCount($model->parent_id);
100 101 }
101 102 });
102 103
104 + static::updated(function ($model) {
105 + if ($model->isDirty('status') && $model->getOriginal('status') === 'open' && $model->status === 'closed') {
106 + // Use persisted attributes without stale stage/board relations from the move.
107 + $closedTask = $model->fresh();
108 + if ($closedTask && $closedTask->status === 'closed') {
109 + do_action('fluent_boards/task_closed', $closedTask);
110 + }
111 + }
112 + });
113 +
103 114 /* global scope for task type which means only type = task will be fetched from everywhere in */
104 115 static::addGlobalScope('type', function (Builder $builder) {
105 116 $builder->where('type', '=', 'task')
106 117 ->orWhere('type', '=', 'roadmap');
@@ -232,8 +243,20 @@
232 243 $boardQuery->excludeTemplates();
233 244 });
234 245 }
235 246
247 + /**
248 + * Limit tasks to active, non-template boards available in this install.
249 + */
250 + public function scopeOnActiveAvailableBoards($query)
251 + {
252 + return $query->whereHas('board', function ($boardQuery) {
253 + $boardQuery->whereNull('archived_at')
254 + ->excludeTemplates()
255 + ->availableInCurrentInstall();
256 + });
257 + }
258 +
236 259 public function assignees()
237 260 {
238 261 return $this->belongsToMany(
239 262 User::class,
@@ -260,8 +283,13 @@
260 283 }
261 284
262 285 public function attachments() //may not need in future
263 286 {
287 + if (!defined('FLUENT_BOARDS_PRO_VERSION')) {
288 + return $this->hasMany(Attachment::class, 'id', 'id')
289 + ->where('id', 0);
290 + }
291 +
264 292 return $this->hasMany(TaskAttachment::class,
265 293 'object_id', 'id')
266 294 ->where('object_type', Constant::OBJECT_TYPE_TASK);
267 295 }
@@ -339,10 +367,15 @@
339 367 return 0;
340 368 }
341 369 }
342 370
371 + /** Use batch-loaded metadata when preparing task-list responses. */
343 372 public function getMetaAttribute()
344 373 {
374 + if ($this->relationLoaded('taskMeta')) {
375 + return $this->getRelation('taskMeta')->pluck('value', 'key');
376 + }
377 +
345 378 return $this->taskMeta()->get()->pluck('value', 'key');
346 379 }
347 380
348 381 public function stage()
@@ -506,8 +539,9 @@
506 539
507 540 return $default;
508 541 }
509 542
543 + /** Persist metadata and invalidate any snapshot loaded for serialization. */
510 544 public function updateMeta($key, $value)
511 545 {
512 546 $exist = TaskMeta::where('task_id', $this->id)->where('key', $key)
513 547 ->first();
@@ -522,8 +556,10 @@
522 556 'value' => $value,
523 557 ]);
524 558 }
525 559
560 + $this->unsetRelation('taskMeta');
561 +
526 562 return $exist;
527 563 }
528 564
529 565 /**
@@ -528,9 +564,9 @@
528 564
529 565 /**
530 566 * Virtual attribute: pinned state from task meta (for API/frontend).
531 567 * Tasks without is_pinned meta are treated as unpinned (0).
532 - * Reads from the already-loaded 'meta' attribute to avoid an extra DB query per task.
568 + * Uses the batch-loaded metadata relation when preparing task lists.
533 569 *
534 570 * @return int 1 if pinned, 0 otherwise
535 571 */
536 572 public function getIsPinnedAttribute()
@@ -860,9 +896,9 @@
860 896 'priority' => [
861 897 'field' => __('Priority', 'fluent-boards'),
862 898 'type' => 'text',
863 899 'rules' => 'optional',
864 - 'description' => __('Priority of the task (urgent | high | medium | low). Leave empty for no priority. Example: "medium" ', 'fluent-boards'),
900 + 'description' => __('Priority of the task (urgent | high | medium | low). Leave empty for no priority. Example: "medium"', 'fluent-boards'),
865 901 ],
866 902 'due_at' => [
867 903 'field' => __('Due Date', 'fluent-boards'),
868 904 'type' => 'date',
@@ -944,10 +980,16 @@
944 980 public function repeatTaskMeta()
945 981 {
946 982 return $this->hasOne(Meta::class, 'object_id', 'id')->where('object_type', Constant::REPEAT_TASK_META);
947 983 }
984 +
985 + /** Reuse batch-loaded repeat settings, including a known missing relation. */
948 986 public function getRepeatTaskMetaAttribute()
949 987 {
988 + if ($this->relationLoaded('repeatTaskMeta')) {
989 + return $this->getRelation('repeatTaskMeta');
990 + }
991 +
950 992 return $this->repeatTaskMeta()->first();
951 993 }
952 994 public function taskCustomFields()
953 995 {