summaryrefslogtreecommitdiff
path: root/app/Formatter
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2015-09-20 22:18:56 -0400
committerFrederic Guillot <fred@kanboard.net>2015-09-20 22:18:56 -0400
commit689687dd4ee186cb9cf5d0230b4648e242c53b10 (patch)
tree3d26bc2079c6eb45790ba604b3a79997be4768ab /app/Formatter
parentf579663adcbc0b202d9a068d734e8f9284dc3a37 (diff)
Add formatters
Diffstat (limited to 'app/Formatter')
-rw-r--r--app/Formatter/FormatterInterface.php14
-rw-r--r--app/Formatter/ProjectGanttFormatter.php90
-rw-r--r--app/Formatter/TaskFilterAutoCompleteFormatter.php33
-rw-r--r--app/Formatter/TaskFilterCalendarEvent.php76
-rw-r--r--app/Formatter/TaskFilterCalendarFormatter.php52
-rw-r--r--app/Formatter/TaskFilterGanttFormatter.php78
-rw-r--r--app/Formatter/TaskFilterICalendarFormatter.php135
7 files changed, 478 insertions, 0 deletions
diff --git a/app/Formatter/FormatterInterface.php b/app/Formatter/FormatterInterface.php
new file mode 100644
index 00000000..4193bd4e
--- /dev/null
+++ b/app/Formatter/FormatterInterface.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Formatter;
+
+/**
+ * Formatter Interface
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+interface FormatterInterface
+{
+ public function format();
+}
diff --git a/app/Formatter/ProjectGanttFormatter.php b/app/Formatter/ProjectGanttFormatter.php
new file mode 100644
index 00000000..652b947d
--- /dev/null
+++ b/app/Formatter/ProjectGanttFormatter.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Formatter;
+
+use Model\Project;
+
+/**
+ * Gantt chart formatter for projects
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class ProjectGanttFormatter extends Project implements FormatterInterface
+{
+ /**
+ * List of projects
+ *
+ * @access private
+ * @var array
+ */
+ private $projects = array();
+
+ /**
+ * Filter projects to generate the Gantt chart
+ *
+ * @access public
+ * @param int[] $project_ids
+ * @return ProjectGanttFormatter
+ */
+ public function filter(array $project_ids)
+ {
+ if (empty($project_ids)) {
+ $this->projects = array();
+ }
+ else {
+
+ $this->projects = $this->db
+ ->table(self::TABLE)
+ ->asc('start_date')
+ ->in('id', $project_ids)
+ ->eq('is_active', self::ACTIVE)
+ ->eq('is_private', 0)
+ ->findAll();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Format projects to be displayed in the Gantt chart
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ $colors = $this->color->getDefaultColors();
+ $bars = array();
+
+ foreach ($this->projects as $project) {
+ $start = empty($project['start_date']) ? time() : strtotime($project['start_date']);
+ $end = empty($project['end_date']) ? $start : strtotime($project['end_date']);
+ $color = next($colors) ?: reset($colors);
+
+ $bars[] = array(
+ 'type' => 'project',
+ 'id' => $project['id'],
+ 'title' => $project['name'],
+ 'start' => array(
+ (int) date('Y', $start),
+ (int) date('n', $start),
+ (int) date('j', $start),
+ ),
+ 'end' => array(
+ (int) date('Y', $end),
+ (int) date('n', $end),
+ (int) date('j', $end),
+ ),
+ 'link' => $this->helper->url->href('project', 'show', array('project_id' => $project['id'])),
+ 'board_link' => $this->helper->url->href('board', 'show', array('project_id' => $project['id'])),
+ 'gantt_link' => $this->helper->url->href('gantt', 'project', array('project_id' => $project['id'])),
+ 'color' => $color,
+ 'not_defined' => empty($project['start_date']) || empty($project['end_date']),
+ 'users' => $this->projectPermission->getProjectUsers($project['id']),
+ );
+ }
+
+ return $bars;
+ }
+}
diff --git a/app/Formatter/TaskFilterAutoCompleteFormatter.php b/app/Formatter/TaskFilterAutoCompleteFormatter.php
new file mode 100644
index 00000000..999a8949
--- /dev/null
+++ b/app/Formatter/TaskFilterAutoCompleteFormatter.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Formatter;
+
+use Model\Task;
+use Model\TaskFilter;
+
+/**
+ * Autocomplete formatter for task filter
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class TaskFilterAutoCompleteFormatter extends TaskFilter implements FormatterInterface
+{
+ /**
+ * Format the tasks for the ajax autocompletion
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ $tasks = $this->query->columns(Task::TABLE.'.id', Task::TABLE.'.title')->findAll();
+
+ foreach ($tasks as &$task) {
+ $task['value'] = $task['title'];
+ $task['label'] = '#'.$task['id'].' - '.$task['title'];
+ }
+
+ return $tasks;
+ }
+}
diff --git a/app/Formatter/TaskFilterCalendarEvent.php b/app/Formatter/TaskFilterCalendarEvent.php
new file mode 100644
index 00000000..8733ee83
--- /dev/null
+++ b/app/Formatter/TaskFilterCalendarEvent.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Formatter;
+
+use Model\TaskFilter;
+
+/**
+ * Common class to handle calendar events
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+abstract class TaskFilterCalendarEvent extends TaskFilter
+{
+ /**
+ * Column used for event start date
+ *
+ * @access protected
+ * @var string
+ */
+ protected $startColumn = 'date_started';
+
+ /**
+ * Column used for event end date
+ *
+ * @access protected
+ * @var string
+ */
+ protected $endColumn = 'date_completed';
+
+ /**
+ * Full day event flag
+ *
+ * @access private
+ * @var boolean
+ */
+ private $fullDay = false;
+
+ /**
+ * Transform results to calendar events
+ *
+ * @access public
+ * @param string $start_column Column name for the start date
+ * @param string $end_column Column name for the end date
+ * @return TaskFilterCalendarEvent
+ */
+ public function setColumns($start_column, $end_column = '')
+ {
+ $this->startColumn = $start_column;
+ $this->endColumn = $end_column ?: $start_column;
+ return $this;
+ }
+
+ /**
+ * When called calendar events will be full day
+ *
+ * @access public
+ * @return TaskFilterCalendarEvent
+ */
+ public function setFullDay()
+ {
+ $this->fullDay = true;
+ return $this;
+ }
+
+ /**
+ * Return true if the events are full day
+ *
+ * @access public
+ * @return boolean
+ */
+ public function isFullDay()
+ {
+ return $this->fullDay;
+ }
+}
diff --git a/app/Formatter/TaskFilterCalendarFormatter.php b/app/Formatter/TaskFilterCalendarFormatter.php
new file mode 100644
index 00000000..f3f42b97
--- /dev/null
+++ b/app/Formatter/TaskFilterCalendarFormatter.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Formatter;
+
+/**
+ * Calendar event formatter for task filter
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class TaskFilterCalendarFormatter extends TaskFilterCalendarEvent implements FormatterInterface
+{
+ /**
+ * Transform tasks to calendar events
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ $events = array();
+
+ foreach ($this->query->findAll() as $task) {
+ $events[] = array(
+ 'timezoneParam' => $this->config->getCurrentTimezone(),
+ 'id' => $task['id'],
+ 'title' => t('#%d', $task['id']).' '.$task['title'],
+ 'backgroundColor' => $this->color->getBackgroundColor($task['color_id']),
+ 'borderColor' => $this->color->getBorderColor($task['color_id']),
+ 'textColor' => 'black',
+ 'url' => $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ 'start' => date($this->getDateTimeFormat(), $task[$this->startColumn]),
+ 'end' => date($this->getDateTimeFormat(), $task[$this->endColumn] ?: time()),
+ 'editable' => $this->isFullDay(),
+ 'allday' => $this->isFullDay(),
+ );
+ }
+
+ return $events;
+ }
+
+ /**
+ * Get DateTime format for event
+ *
+ * @access private
+ * @return string
+ */
+ private function getDateTimeFormat()
+ {
+ return $this->isFullDay() ? 'Y-m-d' : 'Y-m-d\TH:i:s';
+ }
+}
diff --git a/app/Formatter/TaskFilterGanttFormatter.php b/app/Formatter/TaskFilterGanttFormatter.php
new file mode 100644
index 00000000..069daa3d
--- /dev/null
+++ b/app/Formatter/TaskFilterGanttFormatter.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace Formatter;
+
+use Model\TaskFilter;
+
+/**
+ * Gantt chart formatter for task filter
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class TaskFilterGanttFormatter extends TaskFilter implements FormatterInterface
+{
+ /**
+ * Local cache for project columns
+ *
+ * @access private
+ * @var array
+ */
+ private $columns = array();
+
+ /**
+ * Format tasks to be displayed in the Gantt chart
+ *
+ * @access public
+ * @return array
+ */
+ public function format()
+ {
+ $bars = array();
+
+ foreach ($this->query->findAll() as $task) {
+ $bars[] = $this->formatTask($task);
+ }
+
+ return $bars;
+ }
+
+ /**
+ * Format a single task
+ *
+ * @access private
+ * @param array $task
+ * @return array
+ */
+ private function formatTask(array $task)
+ {
+ if (! isset($this->columns[$task['project_id']])) {
+ $this->columns[$task['project_id']] = $this->board->getColumnsList($task['project_id']);
+ }
+
+ $start = $task['date_started'] ?: time();
+ $end = $task['date_due'] ?: $start;
+
+ return array(
+ 'type' => 'task',
+ 'id' => $task['id'],
+ 'title' => $task['title'],
+ 'start' => array(
+ (int) date('Y', $start),
+ (int) date('n', $start),
+ (int) date('j', $start),
+ ),
+ 'end' => array(
+ (int) date('Y', $end),
+ (int) date('n', $end),
+ (int) date('j', $end),
+ ),
+ 'column_title' => $task['column_name'],
+ 'assignee' => $task['assignee_name'] ?: $task['assignee_username'],
+ 'progress' => $this->task->getProgress($task, $this->columns[$task['project_id']]).'%',
+ 'link' => $this->helper->url->href('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])),
+ 'color' => $this->color->getColorProperties($task['color_id']),
+ 'not_defined' => empty($task['date_due']) || empty($task['date_started']),
+ );
+ }
+}
diff --git a/app/Formatter/TaskFilterICalendarFormatter.php b/app/Formatter/TaskFilterICalendarFormatter.php
new file mode 100644
index 00000000..8aed1e20
--- /dev/null
+++ b/app/Formatter/TaskFilterICalendarFormatter.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace Formatter;
+
+use DateTime;
+use Eluceo\iCal\Component\Calendar;
+use Eluceo\iCal\Component\Event;
+use Eluceo\iCal\Property\Event\Attendees;
+
+/**
+ * iCal event formatter for task filter
+ *
+ * @package formatter
+ * @author Frederic Guillot
+ */
+class TaskFilterICalendarFormatter extends TaskFilterCalendarEvent implements FormatterInterface
+{
+ /**
+ * Calendar object
+ *
+ * @access private
+ * @var \Eluceo\iCal\Component\Calendar
+ */
+ private $vCalendar;
+
+ /**
+ * Get Ical events
+ *
+ * @access public
+ * @return string
+ */
+ public function format()
+ {
+ return $this->vCalendar->render();
+ }
+
+ /**
+ * Set calendar object
+ *
+ * @access public
+ * @param \Eluceo\iCal\Component\Calendar $vCalendar
+ * @return TaskFilterICalendarFormatter
+ */
+ public function setCalendar(Calendar $vCalendar)
+ {
+ $this->vCalendar = $vCalendar;
+ return $this;
+ }
+
+ /**
+ * Transform results to ical events
+ *
+ * @access public
+ * @return TaskFilterICalendarFormatter
+ */
+ public function addDateTimeEvents()
+ {
+ foreach ($this->query->findAll() as $task) {
+
+ $start = new DateTime;
+ $start->setTimestamp($task[$this->startColumn]);
+
+ $end = new DateTime;
+ $end->setTimestamp($task[$this->endColumn] ?: time());
+
+ $vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$this->startColumn.'-'.$this->endColumn);
+ $vEvent->setDtStart($start);
+ $vEvent->setDtEnd($end);
+
+ $this->vCalendar->addComponent($vEvent);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Transform results to all day ical events
+ *
+ * @access public
+ * @return TaskFilterICalendarFormatter
+ */
+ public function addFullDayEvents()
+ {
+ foreach ($this->query->findAll() as $task) {
+
+ $date = new DateTime;
+ $date->setTimestamp($task[$this->startColumn]);
+
+ $vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$this->startColumn);
+ $vEvent->setDtStart($date);
+ $vEvent->setDtEnd($date);
+ $vEvent->setNoTime(true);
+
+ $this->vCalendar->addComponent($vEvent);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get common events for task ical events
+ *
+ * @access protected
+ * @param array $task
+ * @param string $uid
+ * @return Event
+ */
+ protected function getTaskIcalEvent(array &$task, $uid)
+ {
+ $dateCreation = new DateTime;
+ $dateCreation->setTimestamp($task['date_creation']);
+
+ $dateModif = new DateTime;
+ $dateModif->setTimestamp($task['date_modification']);
+
+ $vEvent = new Event($uid);
+ $vEvent->setCreated($dateCreation);
+ $vEvent->setModified($dateModif);
+ $vEvent->setUseTimezone(true);
+ $vEvent->setSummary(t('#%d', $task['id']).' '.$task['title']);
+ $vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', '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']);
+ }
+
+ if (! empty($task['creator_id'])) {
+ $attendees = new Attendees;
+ $attendees->add('MAILTO:'.($task['creator_email'] ?: $task['creator_username'].'@kanboard.local'));
+ $vEvent->setAttendees($attendees);
+ }
+
+ return $vEvent;
+ }
+}