Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
21.05% covered (danger)
21.05%
4 / 19
CRAP
33.71% covered (danger)
33.71%
30 / 89
TaskList
0.00% covered (danger)
0.00%
0 / 1
21.05% covered (danger)
21.05%
4 / 19
370.78
33.71% covered (danger)
33.71%
30 / 89
 afterSave
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
6 / 6
 getTasks
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 load
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getNonCompletedTasks
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 getShowMoreCompletedTasks
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getCompletedTasks
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getTasksByStatus
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 findById
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 findByFilter
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 15
 findOverviewLists
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
10 / 10
 findHiddenLists
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 11
 deleteByModule
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 6
 deleteByType
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 6
 afterDelete
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 moveItemIndex
0.00% covered (danger)
0.00%
0 / 1
8.30
60.00% covered (warning)
60.00%
12 / 20
 isHideIfCompleted
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getId
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getTitle
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getColor
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
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;
    }
}