| Code Coverage | ||||||||||
| Classes and Traits | Functions and Methods | Lines | ||||||||
| Total |  | 0.00% | 0 / 1 |  | 21.05% | 4 / 19 | CRAP |  | 33.71% | 30 / 89 | 
| TaskList |  | 0.00% | 0 / 1 |  | 21.05% | 4 / 19 | 370.78 |  | 33.71% | 30 / 89 | 
| afterSave |  | 100.00% | 1 / 1 | 2 |  | 100.00% | 6 / 6 | |||
| getTasks |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 1 / 1 | |||
| load |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 2 | |||
| getNonCompletedTasks |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 1 / 1 | |||
| getShowMoreCompletedTasks |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| getCompletedTasks |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| getTasksByStatus |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| findById |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| findByFilter |  | 0.00% | 0 / 1 | 42 |  | 0.00% | 0 / 15 | |||
| findOverviewLists |  | 100.00% | 1 / 1 | 1 |  | 100.00% | 10 / 10 | |||
| findHiddenLists |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 11 | |||
| deleteByModule |  | 0.00% | 0 / 1 | 12 |  | 0.00% | 0 / 6 | |||
| deleteByType |  | 0.00% | 0 / 1 | 12 |  | 0.00% | 0 / 6 | |||
| afterDelete |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 3 | |||
| moveItemIndex |  | 0.00% | 0 / 1 | 8.30 |  | 60.00% | 12 / 20 | |||
| isHideIfCompleted |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| getId |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| getTitle |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| getColor |  | 0.00% | 0 / 1 | 2 |  | 0.00% | 0 / 1 | |||
| <?php | |
| /** | |
| * @link https://www.humhub.org/ | |
| * @copyright Copyright (c) 2018 HumHub GmbH & Co. KG | |
| * @license https://www.humhub.com/licences | |
| * | |
| */ | |
| namespace humhub\modules\tasks\models\lists; | |
| use humhub\modules\content\components\ActiveQueryContent; | |
| use humhub\modules\content\components\ContentContainerActiveRecord; | |
| use humhub\modules\content\models\ContentContainer; | |
| use humhub\modules\content\models\ContentTag; | |
| use humhub\modules\tasks\models\Sortable; | |
| use humhub\modules\tasks\models\Task; | |
| use yii\db\ActiveQuery; | |
| use yii\db\Expression; | |
| /** | |
| * Class TaskList | |
| * @property int $id | |
| * @property TaskListSettings $addition | |
| */ | |
| class TaskList extends ContentTag implements TaskListInterface, Sortable | |
| { | |
| public $moduleId = 'tasks'; | |
| public $additionClass = TaskListSettings::class; | |
| const FILTER_STATUS_INCLUDE = 'status'; | |
| const FILTER_STATUS_EXCLUDE = 'status'; | |
| public function afterSave($insert, $changedAttributes) | |
| { | |
| // TODO: this can be removed after v1.2.6 | |
| $this->addition->setTag($this); | |
| if($insert) { | |
| $root = new TaskListRoot(['contentContainer' => $this->getContainer()]); | |
| $root->moveItemIndex($this->id, 0); | |
| } | |
| parent::afterSave($insert, $changedAttributes); | |
| } | |
| /** | |
| * @return ActiveQueryContent | |
| */ | |
| public function getTasks() | |
| { | |
| return Task::find()->andWhere(['task_list_id' => $this->id])->readable(); | |
| } | |
| public function load($data, $formName = null) | |
| { | |
| // TODO: this can be removed after v1.2.6 | |
| $this->addition->load($data); | |
| return parent::load($data, $formName); // TODO: Change the autogenerated stub | |
| } | |
| /** | |
| * @return ActiveQueryContent | |
| */ | |
| public function getNonCompletedTasks() | |
| { | |
| return $this->getTasks()->where(['!=', 'task.status', Task::STATUS_COMPLETED])->orderBy(['sort_order' => SORT_ASC, 'updated_at' => SORT_DESC]); | |
| } | |
| /** | |
| * @param $offset int | |
| * @param $limit int | |
| * @return static[] | |
| */ | |
| public function getShowMoreCompletedTasks($offset, $limit) | |
| { | |
| return $this->getCompletedTasks()->orderBy(['task.updated_at' => SORT_DESC])->offset($offset)->limit($limit)->all(); | |
| } | |
| /** | |
| * @return ActiveQuery | |
| */ | |
| public function getCompletedTasks() | |
| { | |
| return $this->getTasksByStatus(Task::STATUS_COMPLETED)->orderBy(['task.updated_at' => SORT_DESC]); | |
| } | |
| /** | |
| * @param $status | |
| * @return ActiveQuery | |
| */ | |
| public function getTasksByStatus($status) | |
| { | |
| return $this->getTasks()->where(['task.status' => $status]); | |
| } | |
| /** | |
| * @param $id | |
| * @param $container | |
| * @return TaskList|null | |
| */ | |
| public static function findById($id, $container) | |
| { | |
| return static::findByContainer($container)->andWhere(['id' => $id])->one(); | |
| } | |
| /** | |
| * @param $container | |
| * @param array $filters | |
| * @return ActiveQuery | |
| */ | |
| public static function findByFilter($container, $filters = []) | |
| { | |
| $query = static::findByContainer($container); | |
| if(isset($filters[static::FILTER_STATUS_EXCLUDE])) { | |
| $includes = Task::$statuses; | |
| $excludes = is_array($filters[static::FILTER_STATUS_EXCLUDE]) ? $filters[static::FILTER_STATUS_EXCLUDE] : [$filters[static::FILTER_STATUS_EXCLUDE]]; | |
| foreach ($excludes as $exclude) { | |
| unset($includes[$exclude]); | |
| } | |
| $filters[static::FILTER_STATUS_INCLUDE] = $includes; | |
| } | |
| if(isset($filters[static::FILTER_STATUS_INCLUDE])) { | |
| $query->leftJoin('task', 'task.task_list_id=content_tag.id'); | |
| $includes = is_array($filters[static::FILTER_STATUS_INCLUDE]) ? $filters[static::FILTER_STATUS_INCLUDE] : [$filters[static::FILTER_STATUS_INCLUDE]]; | |
| $query->andWhere( | |
| ['OR', | |
| ['IS', 'task.id', new Expression("NULL")], | |
| ['IN', 'task.status', $includes] | |
| ]); | |
| } | |
| return $query; | |
| } | |
| /** | |
| * @param $container | |
| * @return ActiveQuery | |
| */ | |
| public static function findOverviewLists(ContentContainerActiveRecord $container) | |
| { | |
| $query = static::findByContainer($container); | |
| $query->leftJoin('task', 'task.task_list_id=content_tag.id'); | |
| $query->leftJoin('task_list_setting', 'task_list_setting.tag_id=content_tag.id'); | |
| $includes = [Task::STATUS_IN_PROGRESS, Task::STATUS_PENDING_REVIEW, Task::STATUS_PENDING]; | |
| $query->andWhere( | |
| ['OR', | |
| ['IN', 'task.status', $includes], | |
| ['IS', 'task.id', new Expression("NULL")], | |
| ['task_list_setting.hide_if_completed' => '0'] | |
| ] | |
| ); | |
| $query->orderBy(['task_list_setting.sort_order' => SORT_ASC]); | |
| return $query; | |
| } | |
| public static function findHiddenLists(ContentContainerActiveRecord $container) | |
| { | |
| $query = static::findByContainer($container); | |
| $query->leftJoin('task t', 't.task_list_id=content_tag.id'); | |
| $query->leftJoin('task_list_setting', 'task_list_setting.tag_id=content_tag.id'); | |
| $includes = [Task::STATUS_IN_PROGRESS, Task::STATUS_PENDING_REVIEW, Task::STATUS_PENDING]; | |
| $subQuery = Task::find()->where(['task_list_id' => new Expression('content_tag.id')])->andWhere(['IN', 'task.status', $includes]); | |
| $query->andWhere( | |
| ['AND', | |
| ['NOT EXISTS', $subQuery], | |
| ['IS NOT', 't.id', new Expression("NULL")], | |
| ['task_list_setting.hide_if_completed' => '1'] | |
| ] | |
| ); | |
| $query->orderBy(['task_list_setting.updated_at' => SORT_ASC]); | |
| return $query; | |
| } | |
| /** | |
| * Deletes all tags by module id | |
| * @param ContentContainerActiveRecord|int $contentContainer | |
| */ | |
| public static function deleteByModule($contentContainer = null) | |
| { | |
| $instance = new static(); | |
| if($contentContainer) { | |
| $container_id = $contentContainer instanceof ContentContainerActiveRecord ? $contentContainer->contentcontainer_id : $contentContainer; | |
| static::deleteAll(['module_id' => $instance->module_id, 'contentcontainer_id' => $container_id]); | |
| } else { | |
| static::deleteAll(['module_id' => $instance->module_id]); | |
| } | |
| } | |
| /** | |
| * Deletes all tags by type | |
| * @param ContentContainerActiveRecord|int $contentContainer | |
| */ | |
| public static function deleteByType($contentContainer = null) | |
| { | |
| $instance = new static(); | |
| if($contentContainer) { | |
| $container_id = $contentContainer instanceof ContentContainerActiveRecord ? $contentContainer->contentcontainer_id : $contentContainer; | |
| static::deleteAll(['type' => $instance->type, 'contentcontainer_id' => $container_id]); | |
| } else { | |
| static::deleteAll(['type' => $instance->type]); | |
| } | |
| } | |
| /** | |
| * @inheritdoc | |
| */ | |
| public function afterDelete() | |
| { | |
| // Workaround for non foreign key support | |
| Task::updateAll(['task_list_id' => new Expression('NULL')], ['task_list_id' => $this->id]); | |
| parent::afterDelete(); | |
| } | |
| public function moveItemIndex($taskId, $newIndex) | |
| { | |
| /** @var $task Task */ | |
| $transaction = Task::getDb()->beginTransaction(); | |
| try { | |
| $task = Task::findOne(['id' => $taskId]); | |
| $tasks = $this->getNonCompletedTasks()->andWhere(['!=', 'task.id', $task->id])->all(); | |
| $task->updateAttributes(['task_list_id' => $this->id]); | |
| // make sure no invalid index is given | |
| if ($newIndex < 0) { | |
| $newIndex = 0; | |
| } else if ($newIndex >= count($tasks) + 1) { | |
| $newIndex = count($tasks) - 1; | |
| } | |
| array_splice($tasks, $newIndex, 0, [$task]); | |
| foreach ($tasks as $index => $item) { | |
| $item->updateAttributes(['sort_order' => $index]); | |
| } | |
| $transaction->commit(); | |
| } catch (\Exception $e) { | |
| $transaction->rollBack(); | |
| throw $e; | |
| } catch (\Throwable $e) { | |
| $transaction->rollBack(); | |
| throw $e; | |
| } | |
| $this->refresh(); | |
| } | |
| public function isHideIfCompleted() | |
| { | |
| return $this->addition->hide_if_completed; | |
| } | |
| public function getId() | |
| { | |
| return $this->id; | |
| } | |
| public function getTitle() | |
| { | |
| return $this->name; | |
| } | |
| public function getColor() | |
| { | |
| return $this->color; | |
| } | |
| } |