diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/Analytic/AverageLeadCycleTimeAnalytic.php | 112 | ||||
-rw-r--r-- | app/Analytic/AverageTimeSpentColumnAnalytic.php | 151 | ||||
-rw-r--r-- | app/Controller/Analytic.php | 6 | ||||
-rw-r--r-- | app/Core/Base.php | 2 | ||||
-rw-r--r-- | app/Locale/fr_FR/translations.php | 4 | ||||
-rw-r--r-- | app/Model/ProjectAnalytic.php | 106 | ||||
-rw-r--r-- | app/Model/ProjectDailyStats.php | 2 | ||||
-rw-r--r-- | app/ServiceProvider/ClassProvider.php | 3 |
8 files changed, 272 insertions, 114 deletions
diff --git a/app/Analytic/AverageLeadCycleTimeAnalytic.php b/app/Analytic/AverageLeadCycleTimeAnalytic.php new file mode 100644 index 00000000..96c803cc --- /dev/null +++ b/app/Analytic/AverageLeadCycleTimeAnalytic.php @@ -0,0 +1,112 @@ +<?php + +namespace Kanboard\Analytic; + +use Kanboard\Core\Base; +use Kanboard\Model\Task; + +/** + * Average Lead and Cycle Time + * + * @package analytic + * @author Frederic Guillot + */ +class AverageLeadCycleTimeAnalytic extends Base +{ + /** + * Build report + * + * @access public + * @param integer $project_id Project id + * @return array + */ + public function build($project_id) + { + $stats = array( + 'count' => 0, + 'total_lead_time' => 0, + 'total_cycle_time' => 0, + 'avg_lead_time' => 0, + 'avg_cycle_time' => 0, + ); + + foreach ($this->getTasks($project_id) as &$task) { + $stats['count']++; + $stats['total_lead_time'] += $this->calculateLeadTime($task); + $stats['total_cycle_time'] += $this->calculateCycleTime($task); + } + + $stats['avg_lead_time'] = $this->calculateAverage($stats, 'total_lead_time'); + $stats['avg_cycle_time'] = $this->calculateAverage($stats, 'total_cycle_time'); + + return $stats; + } + + /** + * Calculate average + * + * @access private + * @param array &$stats + * @param string $field + * @return float + */ + private function calculateAverage(array &$stats, $field) + { + if ($stats['count'] > 0) { + return (int) ($stats[$field] / $stats['count']); + } + + return 0; + } + + /** + * Calculate lead time + * + * @access private + * @param array &$task + * @return integer + */ + private function calculateLeadTime(array &$task) + { + $end = $task['date_completed'] ?: time(); + $start = $task['date_creation']; + + return $end - $start; + } + + /** + * Calculate cycle time + * + * @access private + * @param array &$task + * @return integer + */ + private function calculateCycleTime(array &$task) + { + if (empty($task['date_started'])) { + return 0; + } + + $end = $task['date_completed'] ?: time(); + $start = $task['date_started']; + + return $end - $start; + } + + /** + * Get the 1000 last created tasks + * + * @access private + * @return array + */ + private function getTasks($project_id) + { + return $this->db + ->table(Task::TABLE) + ->columns('date_completed', 'date_creation', 'date_started') + ->eq('project_id', $project_id) + ->desc('id') + ->limit(1000) + ->findAll(); + } +} diff --git a/app/Analytic/AverageTimeSpentColumnAnalytic.php b/app/Analytic/AverageTimeSpentColumnAnalytic.php new file mode 100644 index 00000000..820db801 --- /dev/null +++ b/app/Analytic/AverageTimeSpentColumnAnalytic.php @@ -0,0 +1,151 @@ +<?php + +namespace Kanboard\Analytic; + +use Kanboard\Core\Base; +use Kanboard\Model\Task; + +/** + * Average Time Spent by Column + * + * @package analytic + * @author Frederic Guillot + */ +class AverageTimeSpentColumnAnalytic extends Base +{ + /** + * Build report + * + * @access public + * @param integer $project_id Project id + * @return array + */ + public function build($project_id) + { + $stats = $this->initialize($project_id); + + $this->processTasks($stats, $project_id); + $this->calculateAverage($stats); + + return $stats; + } + + /** + * Initialize default values for each column + * + * @access private + * @param integer $project_id + * @return array + */ + private function initialize($project_id) + { + $stats = array(); + $columns = $this->board->getColumnsList($project_id); + + foreach ($columns as $column_id => $column_title) { + $stats[$column_id] = array( + 'count' => 0, + 'time_spent' => 0, + 'average' => 0, + 'title' => $column_title, + ); + } + + return $stats; + } + + /** + * Calculate time spent for each tasks for each columns + * + * @access private + * @param array $stats + * @param integer $project_id + */ + private function processTasks(array &$stats, $project_id) + { + foreach ($this->getTasks($project_id) as &$task) { + foreach ($this->getTaskTimeByColumns($task) as $column_id => $time_spent) { + if (isset($stats[$column_id])) { + $stats[$column_id]['count']++; + $stats[$column_id]['time_spent'] += $time_spent; + } + } + } + } + + /** + * Calculate averages + * + * @access private + * @param array $stats + */ + private function calculateAverage(array &$stats) + { + foreach ($stats as &$column) { + $this->calculateColumnAverage($column); + } + } + + /** + * Calculate column average + * + * @access private + * @param array $column + */ + private function calculateColumnAverage(array &$column) + { + if ($column['count'] > 0) { + $column['average'] = (int) ($column['time_spent'] / $column['count']); + } + } + + /** + * Get time spent for each column for a given task + * + * @access private + * @param array $task + * @return array + */ + private function getTaskTimeByColumns(array &$task) + { + $columns = $this->transition->getTimeSpentByTask($task['id']); + + if (! isset($columns[$task['column_id']])) { + $columns[$task['column_id']] = 0; + } + + $columns[$task['column_id']] += $this->getTaskTimeSpentInCurrentColumn($task); + + return $columns; + } + + /** + * Calculate time spent of a task in the current column + * + * @access private + * @param array $task + */ + private function getTaskTimeSpentInCurrentColumn(array &$task) + { + $end = $task['date_completed'] ?: time(); + return $end - $task['date_moved']; + } + + /** + * Fetch the last 1000 tasks + * + * @access private + * @param integer $project_id + * @return array + */ + private function getTasks($project_id) + { + return $this->db + ->table(Task::TABLE) + ->columns('id', 'date_completed', 'date_moved', 'column_id') + ->eq('project_id', $project_id) + ->desc('id') + ->limit(1000) + ->findAll(); + } +} diff --git a/app/Controller/Analytic.php b/app/Controller/Analytic.php index f9ea511b..26386029 100644 --- a/app/Controller/Analytic.php +++ b/app/Controller/Analytic.php @@ -37,8 +37,6 @@ class Analytic extends Base $project = $this->getProject(); $values = $this->request->getValues(); - $this->projectDailyStats->updateTotals($project['id'], date('Y-m-d')); - $from = $this->request->getStringParam('from', date('Y-m-d', strtotime('-1week'))); $to = $this->request->getStringParam('to', date('Y-m-d')); @@ -53,7 +51,7 @@ class Analytic extends Base 'to' => $to, ), 'project' => $project, - 'average' => $this->projectAnalytic->getAverageLeadAndCycleTime($project['id']), + 'average' => $this->averageLeadCycleTimeAnalytic->build($project['id']), 'metrics' => $this->projectDailyStats->getRawMetrics($project['id'], $from, $to), 'date_format' => $this->config->get('application_date_format'), 'date_formats' => $this->dateParser->getAvailableFormats(), @@ -72,7 +70,7 @@ class Analytic extends Base $this->response->html($this->layout('analytic/avg_time_columns', array( 'project' => $project, - 'metrics' => $this->projectAnalytic->getAverageTimeSpentByColumn($project['id']), + 'metrics' => $this->averageTimeSpentColumnAnalytic->build($project['id']), 'title' => t('Average time spent into each column for "%s"', $project['name']), ))); } diff --git a/app/Core/Base.php b/app/Core/Base.php index ea8c0abf..2821e5ae 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -13,6 +13,8 @@ use Pimple\Container; * @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic * @property \Kanboard\Analytic\UserDistributionAnalytic $userDistributionAnalytic * @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic + * @property \Kanboard\Analytic\AverageLeadCycleTimeAnalytic $averageLeadCycleTimeAnalytic + * @property \Kanboard\Analytic\AverageTimeSpentColumnAnalytic $averageTimeSpentColumnAnalytic * @property \Kanboard\Core\Action\ActionManager $actionManager * @property \Kanboard\Core\Cache\MemoryCache $memoryCache * @property \Kanboard\Core\Event\EventManager $eventManager diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php index 016c16d7..2724c300 100644 --- a/app/Locale/fr_FR/translations.php +++ b/app/Locale/fr_FR/translations.php @@ -1074,8 +1074,8 @@ return array( 'You were mentioned in a comment on the task #%d' => 'Vous avez été mentionné dans un commentaire de la tâche n°%d', 'Mentioned' => 'Mentionné', 'Compare Estimated Time vs Actual Time' => 'Comparer le temps estimé et le temps actuel', - 'Estimated hours: ' => 'Heures estimées :', - 'Actual hours: ' => 'Heures actuelles :', + 'Estimated hours: ' => 'Heures estimées : ', + 'Actual hours: ' => 'Heures actuelles : ', 'Hours Spent' => 'Heures passées', 'Hours Estimated' => 'Heures estimées', 'Estimated Time' => 'Temps estimé', diff --git a/app/Model/ProjectAnalytic.php b/app/Model/ProjectAnalytic.php deleted file mode 100644 index 5753a5ae..00000000 --- a/app/Model/ProjectAnalytic.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -namespace Kanboard\Model; - -/** - * Project analytic model - * - * @package model - * @author Frederic Guillot - */ -class ProjectAnalytic extends Base -{ - /** - * Get the average lead and cycle time - * - * @access public - * @param integer $project_id - * @return array - */ - public function getAverageLeadAndCycleTime($project_id) - { - $stats = array( - 'count' => 0, - 'total_lead_time' => 0, - 'total_cycle_time' => 0, - 'avg_lead_time' => 0, - 'avg_cycle_time' => 0, - ); - - $tasks = $this->db - ->table(Task::TABLE) - ->columns('date_completed', 'date_creation', 'date_started') - ->eq('project_id', $project_id) - ->desc('id') - ->limit(1000) - ->findAll(); - - foreach ($tasks as &$task) { - $stats['count']++; - $stats['total_lead_time'] += ($task['date_completed'] ?: time()) - $task['date_creation']; - $stats['total_cycle_time'] += empty($task['date_started']) ? 0 : ($task['date_completed'] ?: time()) - $task['date_started']; - } - - $stats['avg_lead_time'] = $stats['count'] > 0 ? (int) ($stats['total_lead_time'] / $stats['count']) : 0; - $stats['avg_cycle_time'] = $stats['count'] > 0 ? (int) ($stats['total_cycle_time'] / $stats['count']) : 0; - - return $stats; - } - - /** - * Get the average time spent into each column - * - * @access public - * @param integer $project_id - * @return array - */ - public function getAverageTimeSpentByColumn($project_id) - { - $stats = array(); - $columns = $this->board->getColumnsList($project_id); - - // Get the time spent of the last move for each tasks - $tasks = $this->db - ->table(Task::TABLE) - ->columns('id', 'date_completed', 'date_moved', 'column_id') - ->eq('project_id', $project_id) - ->desc('id') - ->limit(1000) - ->findAll(); - - // Init values - foreach ($columns as $column_id => $column_title) { - $stats[$column_id] = array( - 'count' => 0, - 'time_spent' => 0, - 'average' => 0, - 'title' => $column_title, - ); - } - - // Get time spent foreach task/column and take into account the last move - foreach ($tasks as &$task) { - $sums = $this->transition->getTimeSpentByTask($task['id']); - - if (! isset($sums[$task['column_id']])) { - $sums[$task['column_id']] = 0; - } - - $sums[$task['column_id']] += ($task['date_completed'] ?: time()) - $task['date_moved']; - - foreach ($sums as $column_id => $time_spent) { - if (isset($stats[$column_id])) { - $stats[$column_id]['count']++; - $stats[$column_id]['time_spent'] += $time_spent; - } - } - } - - // Calculate average for each column - foreach ($columns as $column_id => $column_title) { - $stats[$column_id]['average'] = $stats[$column_id]['count'] > 0 ? (int) ($stats[$column_id]['time_spent'] / $stats[$column_id]['count']) : 0; - } - - return $stats; - } -} diff --git a/app/Model/ProjectDailyStats.php b/app/Model/ProjectDailyStats.php index e79af372..12fecbe6 100644 --- a/app/Model/ProjectDailyStats.php +++ b/app/Model/ProjectDailyStats.php @@ -29,7 +29,7 @@ class ProjectDailyStats extends Base { $this->db->startTransaction(); - $lead_cycle_time = $this->projectAnalytic->getAverageLeadAndCycleTime($project_id); + $lead_cycle_time = $this->averageLeadCycleTimeAnalytic->build($project_id); $exists = $this->db->table(ProjectDailyStats::TABLE) ->eq('day', $date) diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php index ed7f4c08..31cbfa8d 100644 --- a/app/ServiceProvider/ClassProvider.php +++ b/app/ServiceProvider/ClassProvider.php @@ -18,6 +18,8 @@ class ClassProvider implements ServiceProviderInterface 'TaskDistributionAnalytic', 'UserDistributionAnalytic', 'EstimatedTimeComparisonAnalytic', + 'AverageLeadCycleTimeAnalytic', + 'AverageTimeSpentColumnAnalytic', ), 'Model' => array( 'Action', @@ -39,7 +41,6 @@ class ClassProvider implements ServiceProviderInterface 'PasswordReset', 'Project', 'ProjectActivity', - 'ProjectAnalytic', 'ProjectDuplication', 'ProjectDailyColumnStats', 'ProjectDailyStats', |