summaryrefslogtreecommitdiff
path: root/app/Model/TaskPosition.php
blob: c23bc3b52c5472bbe55f54d9baa7445078971ef7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php

namespace Model;

/**
 * Task Position
 *
 * @package  model
 * @author   Frederic Guillot
 */
class TaskPosition extends Base
{
    /**
     * Move a task to another column or to another position
     *
     * @access public
     * @param  integer    $project_id        Project id
     * @param  integer    $task_id           Task id
     * @param  integer    $column_id         Column id
     * @param  integer    $position          Position (must be >= 1)
     * @return boolean
     */
    public function movePosition($project_id, $task_id, $column_id, $position)
    {
        $original_task = $this->taskFinder->getById($task_id);
        $positions = $this->calculatePositions($project_id, $task_id, $column_id, $position);

        if ($positions === false || ! $this->savePositions($positions)) {
            return false;
        }

        $this->fireEvents($original_task, $column_id, $position);

        return true;
    }

    /**
     * Calculate the new position of all tasks
     *
     * @access public
     * @param  integer    $project_id        Project id
     * @param  integer    $task_id           Task id
     * @param  integer    $column_id         Column id
     * @param  integer    $position          Position (must be >= 1)
     * @return array|boolean
     */
    public function calculatePositions($project_id, $task_id, $column_id, $position)
    {
        // The position can't be lower than 1
        if ($position < 1) {
            return false;
        }

        $board = $this->db->table(Board::TABLE)->eq('project_id', $project_id)->asc('position')->findAllByColumn('id');
        $columns = array();

        // For each column fetch all tasks ordered by position
        foreach ($board as $board_column_id) {

            $columns[$board_column_id] = $this->db->table(Task::TABLE)
                          ->eq('is_active', 1)
                          ->eq('project_id', $project_id)
                          ->eq('column_id', $board_column_id)
                          ->neq('id', $task_id)
                          ->asc('position')
                          ->findAllByColumn('id');
        }

        // The column must exists
        if (! isset($columns[$column_id])) {
            return false;
        }

        // We put our task to the new position
        array_splice($columns[$column_id], $position - 1, 0, $task_id);

        return $columns;
    }

    /**
     * Save task positions
     *
     * @access private
     * @param  array       $columns          Sorted tasks
     * @return boolean
     */
    private function savePositions(array $columns)
    {
        return $this->db->transaction(function ($db) use ($columns) {

            foreach ($columns as $column_id => $column) {

                $position = 1;

                foreach ($column as $task_id) {

                    $result = $db->table(Task::TABLE)->eq('id', $task_id)->update(array(
                        'position' => $position,
                        'column_id' => $column_id
                    ));

                    if (! $result) {
                        return false;
                    }

                    $position++;
                }
            }
        });
    }

    /**
     * Fire events
     *
     * @access public
     * @param  array     $task
     * @param  integer   $new_column_id
     * @param  integer   $new_position
     */
    public function fireEvents(array $task, $new_column_id, $new_position)
    {
        $event_data = array(
            'task_id' => $task['id'],
            'project_id' => $task['project_id'],
            'position' => $new_position,
            'column_id' => $new_column_id,
        );

        if ($task['column_id'] != $new_column_id) {
            $this->event->trigger(Task::EVENT_MOVE_COLUMN, $event_data);
        }
        else if ($task['position'] != $new_position) {
            $this->event->trigger(Task::EVENT_MOVE_POSITION, $event_data);
        }
    }
}