summaryrefslogtreecommitdiff
path: root/app/Model
diff options
context:
space:
mode:
Diffstat (limited to 'app/Model')
-rw-r--r--app/Model/TagDuplicationModel.php67
-rw-r--r--app/Model/TaskDuplicationModel.php156
-rw-r--r--app/Model/TaskModel.php2
-rw-r--r--app/Model/TaskProjectDuplicationModel.php60
-rw-r--r--app/Model/TaskProjectMoveModel.php67
-rw-r--r--app/Model/TaskRecurrenceModel.php87
-rw-r--r--app/Model/TaskTagModel.php17
7 files changed, 311 insertions, 145 deletions
diff --git a/app/Model/TagDuplicationModel.php b/app/Model/TagDuplicationModel.php
new file mode 100644
index 00000000..1876391d
--- /dev/null
+++ b/app/Model/TagDuplicationModel.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Base;
+
+/**
+ * Tag Duplication
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class TagDuplicationModel extends Base
+{
+ /**
+ * Link tags to the new tasks
+ *
+ * @access public
+ * @param integer $src_task_id
+ * @param integer $dst_task_id
+ * @param integer $dst_project_id
+ */
+ public function duplicateTaskTagsToAnotherProject($src_task_id, $dst_task_id, $dst_project_id)
+ {
+ $tags = $this->taskTagModel->getTagsByTask($src_task_id);
+
+ foreach ($tags as $tag) {
+ $tag_id = $this->tagModel->getIdByName($dst_project_id, $tag['name']);
+
+ if ($tag_id) {
+ $this->taskTagModel->associateTag($dst_task_id, $tag_id);
+ }
+ }
+ }
+
+ /**
+ * Duplicate tags to the new task
+ *
+ * @access public
+ * @param integer $src_task_id
+ * @param integer $dst_task_id
+ */
+ public function duplicateTaskTags($src_task_id, $dst_task_id)
+ {
+ $tags = $this->taskTagModel->getTagsByTask($src_task_id);
+
+ foreach ($tags as $tag) {
+ $this->taskTagModel->associateTag($dst_task_id, $tag['id']);
+ }
+ }
+
+ /**
+ * Remove tags that are not available in destination project
+ *
+ * @access public
+ * @param integer $task_id
+ * @param integer $dst_project_id
+ */
+ public function syncTaskTagsToAnotherProject($task_id, $dst_project_id)
+ {
+ $tag_ids = $this->taskTagModel->getTagIdsByTaskNotAvailableInProject($task_id, $dst_project_id);
+
+ foreach ($tag_ids as $tag_id) {
+ $this->taskTagModel->dissociateTag($task_id, $tag_id);
+ }
+ }
+}
diff --git a/app/Model/TaskDuplicationModel.php b/app/Model/TaskDuplicationModel.php
index 9a4613e2..0dce891f 100644
--- a/app/Model/TaskDuplicationModel.php
+++ b/app/Model/TaskDuplicationModel.php
@@ -2,10 +2,7 @@
namespace Kanboard\Model;
-use DateTime;
-use DateInterval;
use Kanboard\Core\Base;
-use Kanboard\Event\TaskEvent;
/**
* Task Duplication
@@ -18,10 +15,10 @@ class TaskDuplicationModel extends Base
/**
* Fields to copy when duplicating a task
*
- * @access private
- * @var array
+ * @access protected
+ * @var string[]
*/
- private $fields_to_duplicate = array(
+ protected $fields_to_duplicate = array(
'title',
'description',
'date_due',
@@ -49,106 +46,13 @@ class TaskDuplicationModel extends Base
*/
public function duplicate($task_id)
{
- return $this->save($task_id, $this->copyFields($task_id));
- }
-
- /**
- * Duplicate recurring task
- *
- * @access public
- * @param integer $task_id Task id
- * @return boolean|integer Recurrence task id
- */
- public function duplicateRecurringTask($task_id)
- {
- $values = $this->copyFields($task_id);
-
- if ($values['recurrence_status'] == TaskModel::RECURRING_STATUS_PENDING) {
- $values['recurrence_parent'] = $task_id;
- $values['column_id'] = $this->columnModel->getFirstColumnId($values['project_id']);
- $this->calculateRecurringTaskDueDate($values);
-
- $recurring_task_id = $this->save($task_id, $values);
-
- if ($recurring_task_id > 0) {
- $parent_update = $this->db
- ->table(TaskModel::TABLE)
- ->eq('id', $task_id)
- ->update(array(
- 'recurrence_status' => TaskModel::RECURRING_STATUS_PROCESSED,
- 'recurrence_child' => $recurring_task_id,
- ));
-
- if ($parent_update) {
- return $recurring_task_id;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Duplicate a task to another project
- *
- * @access public
- * @param integer $task_id
- * @param integer $project_id
- * @param integer $swimlane_id
- * @param integer $column_id
- * @param integer $category_id
- * @param integer $owner_id
- * @return boolean|integer
- */
- public function duplicateToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
- {
- $values = $this->copyFields($task_id);
- $values['project_id'] = $project_id;
- $values['column_id'] = $column_id !== null ? $column_id : $values['column_id'];
- $values['swimlane_id'] = $swimlane_id !== null ? $swimlane_id : $values['swimlane_id'];
- $values['category_id'] = $category_id !== null ? $category_id : $values['category_id'];
- $values['owner_id'] = $owner_id !== null ? $owner_id : $values['owner_id'];
-
- $this->checkDestinationProjectValues($values);
-
- return $this->save($task_id, $values);
- }
+ $new_task_id = $this->save($task_id, $this->copyFields($task_id));
- /**
- * Move a task to another project
- *
- * @access public
- * @param integer $task_id
- * @param integer $project_id
- * @param integer $swimlane_id
- * @param integer $column_id
- * @param integer $category_id
- * @param integer $owner_id
- * @return boolean
- */
- public function moveToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
- {
- $task = $this->taskFinderModel->getById($task_id);
-
- $values = array();
- $values['is_active'] = 1;
- $values['project_id'] = $project_id;
- $values['column_id'] = $column_id !== null ? $column_id : $task['column_id'];
- $values['position'] = $this->taskFinderModel->countByColumnId($project_id, $values['column_id']) + 1;
- $values['swimlane_id'] = $swimlane_id !== null ? $swimlane_id : $task['swimlane_id'];
- $values['category_id'] = $category_id !== null ? $category_id : $task['category_id'];
- $values['owner_id'] = $owner_id !== null ? $owner_id : $task['owner_id'];
-
- $this->checkDestinationProjectValues($values);
-
- if ($this->db->table(TaskModel::TABLE)->eq('id', $task['id'])->update($values)) {
- $this->container['dispatcher']->dispatch(
- TaskModel::EVENT_MOVE_PROJECT,
- new TaskEvent(array_merge($task, $values, array('task_id' => $task['id'])))
- );
+ if ($new_task_id !== false) {
+ $this->tagDuplicationModel->duplicateTaskTags($task_id, $new_task_id);
}
- return true;
+ return $new_task_id;
}
/**
@@ -195,49 +99,13 @@ class TaskDuplicationModel extends Base
}
/**
- * Calculate new due date for new recurrence task
- *
- * @access public
- * @param array $values Task fields
- */
- public function calculateRecurringTaskDueDate(array &$values)
- {
- if (! empty($values['date_due']) && $values['recurrence_factor'] != 0) {
- if ($values['recurrence_basedate'] == TaskModel::RECURRING_BASEDATE_TRIGGERDATE) {
- $values['date_due'] = time();
- }
-
- $factor = abs($values['recurrence_factor']);
- $subtract = $values['recurrence_factor'] < 0;
-
- switch ($values['recurrence_timeframe']) {
- case TaskModel::RECURRING_TIMEFRAME_MONTHS:
- $interval = 'P' . $factor . 'M';
- break;
- case TaskModel::RECURRING_TIMEFRAME_YEARS:
- $interval = 'P' . $factor . 'Y';
- break;
- default:
- $interval = 'P' . $factor . 'D';
- }
-
- $date_due = new DateTime();
- $date_due->setTimestamp($values['date_due']);
-
- $subtract ? $date_due->sub(new DateInterval($interval)) : $date_due->add(new DateInterval($interval));
-
- $values['date_due'] = $date_due->getTimestamp();
- }
- }
-
- /**
* Duplicate fields for the new task
*
- * @access private
+ * @access protected
* @param integer $task_id Task id
* @return array
*/
- private function copyFields($task_id)
+ protected function copyFields($task_id)
{
$task = $this->taskFinderModel->getById($task_id);
$values = array();
@@ -252,16 +120,16 @@ class TaskDuplicationModel extends Base
/**
* Create the new task and duplicate subtasks
*
- * @access private
+ * @access protected
* @param integer $task_id Task id
* @param array $values Form values
* @return boolean|integer
*/
- private function save($task_id, array $values)
+ protected function save($task_id, array $values)
{
$new_task_id = $this->taskCreationModel->create($values);
- if ($new_task_id) {
+ if ($new_task_id !== false) {
$this->subtaskModel->duplicate($task_id, $new_task_id);
}
diff --git a/app/Model/TaskModel.php b/app/Model/TaskModel.php
index b0e7772a..b945ee44 100644
--- a/app/Model/TaskModel.php
+++ b/app/Model/TaskModel.php
@@ -215,7 +215,7 @@ class TaskModel extends Base
$task_ids = $this->taskFinderModel->getAllIds($src_project_id, array(TaskModel::STATUS_OPEN, TaskModel::STATUS_CLOSED));
foreach ($task_ids as $task_id) {
- if (! $this->taskDuplicationModel->duplicateToProject($task_id, $dst_project_id)) {
+ if (! $this->taskProjectDuplicationModel->duplicateToProject($task_id, $dst_project_id)) {
return false;
}
}
diff --git a/app/Model/TaskProjectDuplicationModel.php b/app/Model/TaskProjectDuplicationModel.php
new file mode 100644
index 00000000..8ebed255
--- /dev/null
+++ b/app/Model/TaskProjectDuplicationModel.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Kanboard\Model;
+
+/**
+ * Task Project Duplication
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class TaskProjectDuplicationModel extends TaskDuplicationModel
+{
+ /**
+ * Duplicate a task to another project
+ *
+ * @access public
+ * @param integer $task_id
+ * @param integer $project_id
+ * @param integer $swimlane_id
+ * @param integer $column_id
+ * @param integer $category_id
+ * @param integer $owner_id
+ * @return boolean|integer
+ */
+ public function duplicateToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
+ {
+ $values = $this->prepare($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
+ $this->checkDestinationProjectValues($values);
+ $new_task_id = $this->save($task_id, $values);
+
+ if ($new_task_id !== false) {
+ $this->tagDuplicationModel->duplicateTaskTagsToAnotherProject($task_id, $new_task_id, $project_id);
+ }
+
+ return $new_task_id;
+ }
+
+ /**
+ * Prepare values before duplication
+ *
+ * @access protected
+ * @param integer $task_id
+ * @param integer $project_id
+ * @param integer $swimlane_id
+ * @param integer $column_id
+ * @param integer $category_id
+ * @param integer $owner_id
+ * @return array
+ */
+ protected function prepare($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id)
+ {
+ $values = $this->copyFields($task_id);
+ $values['project_id'] = $project_id;
+ $values['column_id'] = $column_id !== null ? $column_id : $values['column_id'];
+ $values['swimlane_id'] = $swimlane_id !== null ? $swimlane_id : $values['swimlane_id'];
+ $values['category_id'] = $category_id !== null ? $category_id : $values['category_id'];
+ $values['owner_id'] = $owner_id !== null ? $owner_id : $values['owner_id'];
+ return $values;
+ }
+}
diff --git a/app/Model/TaskProjectMoveModel.php b/app/Model/TaskProjectMoveModel.php
new file mode 100644
index 00000000..7e9714d6
--- /dev/null
+++ b/app/Model/TaskProjectMoveModel.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Event\TaskEvent;
+
+/**
+ * Task Project Move
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class TaskProjectMoveModel extends TaskDuplicationModel
+{
+ /**
+ * Move a task to another project
+ *
+ * @access public
+ * @param integer $task_id
+ * @param integer $project_id
+ * @param integer $swimlane_id
+ * @param integer $column_id
+ * @param integer $category_id
+ * @param integer $owner_id
+ * @return boolean
+ */
+ public function moveToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
+ {
+ $task = $this->taskFinderModel->getById($task_id);
+ $values = $this->prepare($project_id, $swimlane_id, $column_id, $category_id, $owner_id, $task);
+
+ $this->checkDestinationProjectValues($values);
+ $this->tagDuplicationModel->syncTaskTagsToAnotherProject($task_id, $project_id);
+
+ if ($this->db->table(TaskModel::TABLE)->eq('id', $task['id'])->update($values)) {
+ $event = new TaskEvent(array_merge($task, $values, array('task_id' => $task['id'])));
+ $this->dispatcher->dispatch(TaskModel::EVENT_MOVE_PROJECT, $event);
+ }
+
+ return true;
+ }
+
+ /**
+ * Prepare new task values
+ *
+ * @access protected
+ * @param integer $project_id
+ * @param integer $swimlane_id
+ * @param integer $column_id
+ * @param integer $category_id
+ * @param integer $owner_id
+ * @param array $task
+ * @return array
+ */
+ protected function prepare($project_id, $swimlane_id, $column_id, $category_id, $owner_id, array $task)
+ {
+ $values = array();
+ $values['is_active'] = 1;
+ $values['project_id'] = $project_id;
+ $values['column_id'] = $column_id !== null ? $column_id : $task['column_id'];
+ $values['position'] = $this->taskFinderModel->countByColumnId($project_id, $values['column_id']) + 1;
+ $values['swimlane_id'] = $swimlane_id !== null ? $swimlane_id : $task['swimlane_id'];
+ $values['category_id'] = $category_id !== null ? $category_id : $task['category_id'];
+ $values['owner_id'] = $owner_id !== null ? $owner_id : $task['owner_id'];
+ return $values;
+ }
+}
diff --git a/app/Model/TaskRecurrenceModel.php b/app/Model/TaskRecurrenceModel.php
new file mode 100644
index 00000000..a5f2ab90
--- /dev/null
+++ b/app/Model/TaskRecurrenceModel.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Kanboard\Model;
+
+use DateInterval;
+use DateTime;
+
+/**
+ * Task Recurrence
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class TaskRecurrenceModel extends TaskDuplicationModel
+{
+ /**
+ * Duplicate recurring task
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @return boolean|integer Recurrence task id
+ */
+ public function duplicateRecurringTask($task_id)
+ {
+ $values = $this->copyFields($task_id);
+
+ if ($values['recurrence_status'] == TaskModel::RECURRING_STATUS_PENDING) {
+ $values['recurrence_parent'] = $task_id;
+ $values['column_id'] = $this->columnModel->getFirstColumnId($values['project_id']);
+ $this->calculateRecurringTaskDueDate($values);
+
+ $recurring_task_id = $this->save($task_id, $values);
+
+ if ($recurring_task_id > 0) {
+ $parent_update = $this->db
+ ->table(TaskModel::TABLE)
+ ->eq('id', $task_id)
+ ->update(array(
+ 'recurrence_status' => TaskModel::RECURRING_STATUS_PROCESSED,
+ 'recurrence_child' => $recurring_task_id,
+ ));
+
+ if ($parent_update) {
+ return $recurring_task_id;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculate new due date for new recurrence task
+ *
+ * @access public
+ * @param array $values Task fields
+ */
+ public function calculateRecurringTaskDueDate(array &$values)
+ {
+ if (! empty($values['date_due']) && $values['recurrence_factor'] != 0) {
+ if ($values['recurrence_basedate'] == TaskModel::RECURRING_BASEDATE_TRIGGERDATE) {
+ $values['date_due'] = time();
+ }
+
+ $factor = abs($values['recurrence_factor']);
+ $subtract = $values['recurrence_factor'] < 0;
+
+ switch ($values['recurrence_timeframe']) {
+ case TaskModel::RECURRING_TIMEFRAME_MONTHS:
+ $interval = 'P' . $factor . 'M';
+ break;
+ case TaskModel::RECURRING_TIMEFRAME_YEARS:
+ $interval = 'P' . $factor . 'Y';
+ break;
+ default:
+ $interval = 'P' . $factor . 'D';
+ }
+
+ $date_due = new DateTime();
+ $date_due->setTimestamp($values['date_due']);
+
+ $subtract ? $date_due->sub(new DateInterval($interval)) : $date_due->add(new DateInterval($interval));
+
+ $values['date_due'] = $date_due->getTimestamp();
+ }
+ }
+}
diff --git a/app/Model/TaskTagModel.php b/app/Model/TaskTagModel.php
index 2a08e867..0553cc6c 100644
--- a/app/Model/TaskTagModel.php
+++ b/app/Model/TaskTagModel.php
@@ -20,6 +20,23 @@ class TaskTagModel extends Base
const TABLE = 'task_has_tags';
/**
+ * Get all tags not available in a project
+ *
+ * @access public
+ * @param integer $task_id
+ * @param integer $project_id
+ * @return array
+ */
+ public function getTagIdsByTaskNotAvailableInProject($task_id, $project_id)
+ {
+ return $this->db->table(TagModel::TABLE)
+ ->eq(self::TABLE.'.task_id', $task_id)
+ ->notIn(TagModel::TABLE.'.project_id', array(0, $project_id))
+ ->join(self::TABLE, 'tag_id', 'id')
+ ->findAllByColumn(TagModel::TABLE.'.id');
+ }
+
+ /**
* Get all tags associated to a task
*
* @access public