summaryrefslogtreecommitdiff
path: root/app/Formatter
diff options
context:
space:
mode:
Diffstat (limited to 'app/Formatter')
-rw-r--r--app/Formatter/BaseFormatter.php17
-rw-r--r--app/Formatter/BoardColumnFormatter.php94
-rw-r--r--app/Formatter/BoardFormatter.php25
-rw-r--r--app/Formatter/BoardSwimlaneFormatter.php120
-rw-r--r--app/Formatter/BoardTaskFormatter.php96
-rw-r--r--app/Formatter/TaskAutoCompleteFormatter.php9
-rw-r--r--app/Formatter/TaskICalFormatter.php17
7 files changed, 364 insertions, 14 deletions
diff --git a/app/Formatter/BaseFormatter.php b/app/Formatter/BaseFormatter.php
index a9f0ad15..89c48437 100644
--- a/app/Formatter/BaseFormatter.php
+++ b/app/Formatter/BaseFormatter.php
@@ -3,8 +3,8 @@
namespace Kanboard\Formatter;
use Kanboard\Core\Base;
-use Kanboard\Core\Filter\FormatterInterface;
use PicoDb\Table;
+use Pimple\Container;
/**
* Class BaseFormatter
@@ -23,11 +23,24 @@ abstract class BaseFormatter extends Base
protected $query;
/**
+ * Get object instance
+ *
+ * @static
+ * @access public
+ * @param Container $container
+ * @return static
+ */
+ public static function getInstance(Container $container)
+ {
+ return new static($container);
+ }
+
+ /**
* Set query
*
* @access public
* @param Table $query
- * @return FormatterInterface
+ * @return $this
*/
public function withQuery(Table $query)
{
diff --git a/app/Formatter/BoardColumnFormatter.php b/app/Formatter/BoardColumnFormatter.php
new file mode 100644
index 00000000..d49a577a
--- /dev/null
+++ b/app/Formatter/BoardColumnFormatter.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Kanboard\Formatter;
+
+use Kanboard\Core\Filter\FormatterInterface;
+
+/**
+ * Board Column Formatter
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class BoardColumnFormatter extends BaseFormatter implements FormatterInterface
+{
+ protected $swimlaneId = 0;
+ protected $columns = array();
+ protected $tasks = array();
+ protected $tags = array();
+
+ /**
+ * Set swimlaneId
+ *
+ * @access public
+ * @param integer $swimlaneId
+ * @return $this
+ */
+ public function withSwimlaneId($swimlaneId)
+ {
+ $this->swimlaneId = $swimlaneId;
+ return $this;
+ }
+
+ /**
+ * Set columns
+ *
+ * @access public
+ * @param array $columns
+ * @return $this
+ */
+ public function withColumns(array $columns)
+ {
+ $this->columns = $columns;
+ return $this;
+ }
+
+ /**
+ * Set tasks
+ *
+ * @access public
+ * @param array $tasks
+ * @return $this
+ */
+ public function withTasks(array $tasks)
+ {
+ $this->tasks = $tasks;
+ return $this;
+ }
+
+ /**
+ * Set tags
+ *
+ * @access public
+ * @param array $tags
+ * @return $this
+ */
+ public function withTags(array $tags)
+ {
+ $this->tags = $tags;
+ return $this;
+ }
+
+ /**
+ * Apply formatter
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ foreach ($this->columns as &$column) {
+ $column['tasks'] = BoardTaskFormatter::getInstance($this->container)
+ ->withTasks($this->tasks)
+ ->withTags($this->tags)
+ ->withSwimlaneId($this->swimlaneId)
+ ->withColumnId($column['id'])
+ ->format();
+
+ $column['nb_tasks'] = count($column['tasks']);
+ $column['score'] = (int) array_column_sum($column['tasks'], 'score');
+ }
+
+ return $this->columns;
+ }
+}
diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php
index dbc7cf21..df443a52 100644
--- a/app/Formatter/BoardFormatter.php
+++ b/app/Formatter/BoardFormatter.php
@@ -28,7 +28,7 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface
* @param integer $projectId
* @return $this
*/
- public function setProjectId($projectId)
+ public function withProjectId($projectId)
{
$this->projectId = $projectId;
return $this;
@@ -42,15 +42,28 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface
*/
public function format()
{
+ $swimlanes = $this->swimlaneModel->getSwimlanes($this->projectId);
+ $columns = $this->columnModel->getAll($this->projectId);
+
+ if (empty($swimlanes) || empty($columns)) {
+ return array();
+ }
+
+ $this->hook->reference('formatter:board:query', $this->query);
+
$tasks = $this->query
->eq(TaskModel::TABLE.'.project_id', $this->projectId)
->asc(TaskModel::TABLE.'.position')
->findAll();
- return $this->boardModel->getBoard($this->projectId, function ($project_id, $column_id, $swimlane_id) use ($tasks) {
- return array_filter($tasks, function (array $task) use ($column_id, $swimlane_id) {
- return $task['column_id'] == $column_id && $task['swimlane_id'] == $swimlane_id;
- });
- });
+ $task_ids = array_column($tasks, 'id');
+ $tags = $this->taskTagModel->getTagsByTasks($task_ids);
+
+ return BoardSwimlaneFormatter::getInstance($this->container)
+ ->withSwimlanes($swimlanes)
+ ->withColumns($columns)
+ ->withTasks($tasks)
+ ->withTags($tags)
+ ->format();
}
}
diff --git a/app/Formatter/BoardSwimlaneFormatter.php b/app/Formatter/BoardSwimlaneFormatter.php
new file mode 100644
index 00000000..c2abb444
--- /dev/null
+++ b/app/Formatter/BoardSwimlaneFormatter.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace Kanboard\Formatter;
+
+use Kanboard\Core\Filter\FormatterInterface;
+
+/**
+ * Board Swimlane Formatter
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class BoardSwimlaneFormatter extends BaseFormatter implements FormatterInterface
+{
+ protected $swimlanes = array();
+ protected $columns = array();
+ protected $tasks = array();
+ protected $tags = array();
+
+ /**
+ * Set swimlanes
+ *
+ * @access public
+ * @param array $swimlanes
+ * @return $this
+ */
+ public function withSwimlanes($swimlanes)
+ {
+ $this->swimlanes = $swimlanes;
+ return $this;
+ }
+
+ /**
+ * Set columns
+ *
+ * @access public
+ * @param array $columns
+ * @return $this
+ */
+ public function withColumns($columns)
+ {
+ $this->columns = $columns;
+ return $this;
+ }
+
+ /**
+ * Set tasks
+ *
+ * @access public
+ * @param array $tasks
+ * @return $this
+ */
+ public function withTasks(array $tasks)
+ {
+ $this->tasks = $tasks;
+ return $this;
+ }
+
+ /**
+ * Set tags
+ *
+ * @access public
+ * @param array $tags
+ * @return $this
+ */
+ public function withTags(array $tags)
+ {
+ $this->tags = $tags;
+ return $this;
+ }
+
+ /**
+ * Apply formatter
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ $nb_swimlanes = count($this->swimlanes);
+ $nb_columns = count($this->columns);
+
+ foreach ($this->swimlanes as &$swimlane) {
+ $swimlane['columns'] = BoardColumnFormatter::getInstance($this->container)
+ ->withSwimlaneId($swimlane['id'])
+ ->withColumns($this->columns)
+ ->withTasks($this->tasks)
+ ->withTags($this->tags)
+ ->format();
+
+ $swimlane['nb_swimlanes'] = $nb_swimlanes;
+ $swimlane['nb_columns'] = $nb_columns;
+ $swimlane['nb_tasks'] = array_column_sum($swimlane['columns'], 'nb_tasks');
+ $swimlane['score'] = array_column_sum($swimlane['columns'], 'score');
+
+ $this->calculateStatsByColumnAcrossSwimlanes($swimlane['columns']);
+ }
+
+ return $this->swimlanes;
+ }
+
+ /**
+ * Calculate stats for each column acrosss all swimlanes
+ *
+ * @access protected
+ * @param array $columns
+ */
+ protected function calculateStatsByColumnAcrossSwimlanes(array $columns)
+ {
+ foreach ($columns as $columnIndex => $column) {
+ if (! isset($this->swimlanes[0]['columns'][$columnIndex]['column_nb_tasks'])) {
+ $this->swimlanes[0]['columns'][$columnIndex]['column_nb_tasks'] = 0;
+ $this->swimlanes[0]['columns'][$columnIndex]['column_score'] = 0;
+ }
+
+ $this->swimlanes[0]['columns'][$columnIndex]['column_nb_tasks'] += $column['nb_tasks'];
+ $this->swimlanes[0]['columns'][$columnIndex]['column_score'] += $column['score'];
+ }
+ }
+}
diff --git a/app/Formatter/BoardTaskFormatter.php b/app/Formatter/BoardTaskFormatter.php
new file mode 100644
index 00000000..3bf171b1
--- /dev/null
+++ b/app/Formatter/BoardTaskFormatter.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace Kanboard\Formatter;
+
+use Kanboard\Core\Filter\FormatterInterface;
+
+/**
+ * Board Task Formatter
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class BoardTaskFormatter extends BaseFormatter implements FormatterInterface
+{
+ protected $tasks = array();
+ protected $tags = array();
+ protected $columnId = 0;
+ protected $swimlaneId = 0;
+
+ /**
+ * Set tags
+ *
+ * @access public
+ * @param array $tags
+ * @return $this
+ */
+ public function withTags(array $tags)
+ {
+ $this->tags = $tags;
+ return $this;
+ }
+
+ /**
+ * Set tasks
+ *
+ * @access public
+ * @param array $tasks
+ * @return $this
+ */
+ public function withTasks(array $tasks)
+ {
+ $this->tasks = $tasks;
+ return $this;
+ }
+
+ /**
+ * Set columnId
+ *
+ * @access public
+ * @param integer $columnId
+ * @return $this
+ */
+ public function withColumnId($columnId)
+ {
+ $this->columnId = $columnId;
+ return $this;
+ }
+
+ /**
+ * Set swimlaneId
+ *
+ * @access public
+ * @param integer $swimlaneId
+ * @return $this
+ */
+ public function withSwimlaneId($swimlaneId)
+ {
+ $this->swimlaneId = $swimlaneId;
+ return $this;
+ }
+
+ /**
+ * Apply formatter
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ $tasks = array_values(array_filter($this->tasks, array($this, 'filterTasks')));
+ array_merge_relation($tasks, $this->tags, 'tags', 'id');
+ return $tasks;
+ }
+
+ /**
+ * Keep only tasks of the given column and swimlane
+ *
+ * @access protected
+ * @param array $task
+ * @return bool
+ */
+ protected function filterTasks(array $task)
+ {
+ return $task['column_id'] == $this->columnId && $task['swimlane_id'] == $this->swimlaneId;
+ }
+}
diff --git a/app/Formatter/TaskAutoCompleteFormatter.php b/app/Formatter/TaskAutoCompleteFormatter.php
index 4f1c4c69..2d9f7341 100644
--- a/app/Formatter/TaskAutoCompleteFormatter.php
+++ b/app/Formatter/TaskAutoCompleteFormatter.php
@@ -3,6 +3,7 @@
namespace Kanboard\Formatter;
use Kanboard\Core\Filter\FormatterInterface;
+use Kanboard\Model\ProjectModel;
use Kanboard\Model\TaskModel;
/**
@@ -21,11 +22,15 @@ class TaskAutoCompleteFormatter extends BaseFormatter implements FormatterInterf
*/
public function format()
{
- $tasks = $this->query->columns(TaskModel::TABLE.'.id', TaskModel::TABLE.'.title')->findAll();
+ $tasks = $this->query->columns(
+ TaskModel::TABLE.'.id',
+ TaskModel::TABLE.'.title',
+ ProjectModel::TABLE.'.name AS project_name'
+ )->asc(TaskModel::TABLE.'.id')->findAll();
foreach ($tasks as &$task) {
$task['value'] = $task['title'];
- $task['label'] = '#'.$task['id'].' - '.$task['title'];
+ $task['label'] = $task['project_name'].' > #'.$task['id'].' '.$task['title'];
}
return $tasks;
diff --git a/app/Formatter/TaskICalFormatter.php b/app/Formatter/TaskICalFormatter.php
index 890674c7..ad2a4449 100644
--- a/app/Formatter/TaskICalFormatter.php
+++ b/app/Formatter/TaskICalFormatter.php
@@ -6,6 +6,7 @@ use DateTime;
use Eluceo\iCal\Component\Calendar;
use Eluceo\iCal\Component\Event;
use Eluceo\iCal\Property\Event\Attendees;
+use Eluceo\iCal\Property\Event\Organizer;
use Kanboard\Core\Filter\FormatterInterface;
/**
@@ -117,16 +118,24 @@ class TaskICalFormatter extends BaseTaskCalendarFormatter implements FormatterIn
$vEvent->setModified($dateModif);
$vEvent->setUseTimezone(true);
$vEvent->setSummary(t('#%d', $task['id']).' '.$task['title']);
+ $vEvent->setDescription($task['description']);
+ $vEvent->setDescriptionHTML($this->helper->text->markdown($task['description']));
$vEvent->setUrl($this->helper->url->base().$this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
if (! empty($task['owner_id'])) {
- $vEvent->setOrganizer($task['assignee_name'] ?: $task['assignee_username'], $task['assignee_email']);
+ $attendees = new Attendees;
+ $attendees->add(
+ 'MAILTO:'.($task['assignee_email'] ?: $task['assignee_username'].'@kanboard.local'),
+ array('CN' => $task['assignee_name'] ?: $task['assignee_username'])
+ );
+ $vEvent->setAttendees($attendees);
}
if (! empty($task['creator_id'])) {
- $attendees = new Attendees;
- $attendees->add('MAILTO:'.($task['creator_email'] ?: $task['creator_username'].'@kanboard.local'));
- $vEvent->setAttendees($attendees);
+ $vEvent->setOrganizer(new Organizer(
+ 'MAILTO:' . $task['creator_email'] ?: $task['creator_username'].'@kanboard.local',
+ array('CN' => $task['creator_name'] ?: $task['creator_username'])
+ ));
}
return $vEvent;