Move analytic logic to separate classes

This commit is contained in:
Frederic Guillot
2016-01-15 21:03:19 -05:00
parent 1bbd4faf56
commit c58478c0ab
13 changed files with 424 additions and 134 deletions

View File

@@ -0,0 +1,50 @@
<?php
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
use Kanboard\Model\Task;
/**
* Estimated/Spent Time Comparison
*
* @package analytic
* @author Frederic Guillot
*/
class EstimatedTimeComparisonAnalytic extends Base
{
/**
* Build report
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function build($project_id)
{
$rows = $this->db->table(Task::TABLE)
->columns('SUM(time_estimated) AS time_estimated', 'SUM(time_spent) AS time_spent', 'is_active')
->eq('project_id', $project_id)
->groupBy('is_active')
->findAll();
$metrics = array(
'open' => array(
'time_spent' => 0,
'time_estimated' => 0,
),
'closed' => array(
'time_spent' => 0,
'time_estimated' => 0,
),
);
foreach ($rows as $row) {
$key = $row['is_active'] == Task::STATUS_OPEN ? 'open' : 'closed';
$metrics[$key]['time_spent'] = $row['time_spent'];
$metrics[$key]['time_estimated'] = $row['time_estimated'];
}
return $metrics;
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
/**
* Task Distribution
*
* @package analytic
* @author Frederic Guillot
*/
class TaskDistributionAnalytic extends Base
{
/**
* Build report
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function build($project_id)
{
$metrics = array();
$total = 0;
$columns = $this->board->getColumns($project_id);
foreach ($columns as $column) {
$nb_tasks = $this->taskFinder->countByColumnId($project_id, $column['id']);
$total += $nb_tasks;
$metrics[] = array(
'column_title' => $column['title'],
'nb_tasks' => $nb_tasks,
);
}
if ($total === 0) {
return array();
}
foreach ($metrics as &$metric) {
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
}
return $metrics;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Kanboard\Analytic;
use Kanboard\Core\Base;
/**
* User Distribution
*
* @package analytic
* @author Frederic Guillot
*/
class UserDistributionAnalytic extends Base
{
/**
* Build Report
*
* @access public
* @param integer $project_id
* @return array
*/
public function build($project_id)
{
$metrics = array();
$total = 0;
$tasks = $this->taskFinder->getAll($project_id);
$users = $this->projectUserRole->getAssignableUsersList($project_id);
foreach ($tasks as $task) {
$user = isset($users[$task['owner_id']]) ? $users[$task['owner_id']] : $users[0];
$total++;
if (! isset($metrics[$user])) {
$metrics[$user] = array(
'nb_tasks' => 0,
'percentage' => 0,
'user' => $user,
);
}
$metrics[$user]['nb_tasks']++;
}
if ($total === 0) {
return array();
}
foreach ($metrics as &$metric) {
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
}
ksort($metrics);
return array_values($metrics);
}
}

View File

@@ -88,7 +88,7 @@ class Analytic extends Base
$this->response->html($this->layout('analytic/tasks', array(
'project' => $project,
'metrics' => $this->projectAnalytic->getTaskRepartition($project['id']),
'metrics' => $this->taskDistributionAnalytic->build($project['id']),
'title' => t('Task repartition for "%s"', $project['name']),
)));
}
@@ -104,7 +104,7 @@ class Analytic extends Base
$this->response->html($this->layout('analytic/users', array(
'project' => $project,
'metrics' => $this->projectAnalytic->getUserRepartition($project['id']),
'metrics' => $this->userDistributionAnalytic->build($project['id']),
'title' => t('User repartition for "%s"', $project['name']),
)));
}
@@ -177,7 +177,7 @@ class Analytic extends Base
{
$project = $this->getProject();
$params = $this->getProjectFilters('analytic', 'compareHours');
$query = $this->taskFilter->search('status:all')->filterByProject($params['project']['id'])->getQuery();
$query = $this->taskFilter->create()->filterByProject($params['project']['id'])->getQuery();
$paginator = $this->paginator
->setUrl('analytic', 'compareHours', array('project_id' => $project['id']))
@@ -186,12 +186,10 @@ class Analytic extends Base
->setQuery($query)
->calculate();
$stats = $this->projectAnalytic->getHoursByStatus($project['id']);
$this->response->html($this->layout('analytic/compare_hours', array(
'project' => $project,
'paginator' => $paginator,
'metrics' => $stats,
'metrics' => $this->estimatedTimeComparisonAnalytic->build($project['id']),
'title' => t('Compare hours for "%s"', $project['name']),
)));
}

View File

@@ -10,6 +10,9 @@ use Pimple\Container;
* @package core
* @author Frederic Guillot
*
* @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic
* @property \Kanboard\Analytic\UserDistributionAnalytic $userDistributionAnalytic
* @property \Kanboard\Analytic\EstimatedTimeComparisonAnalytic $estimatedTimeComparisonAnalytic
* @property \Kanboard\Core\Action\ActionManager $actionManager
* @property \Kanboard\Core\Cache\MemoryCache $memoryCache
* @property \Kanboard\Core\Event\EventManager $eventManager

View File

@@ -10,82 +10,6 @@ namespace Kanboard\Model;
*/
class ProjectAnalytic extends Base
{
/**
* Get tasks repartition
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getTaskRepartition($project_id)
{
$metrics = array();
$total = 0;
$columns = $this->board->getColumns($project_id);
foreach ($columns as $column) {
$nb_tasks = $this->taskFinder->countByColumnId($project_id, $column['id']);
$total += $nb_tasks;
$metrics[] = array(
'column_title' => $column['title'],
'nb_tasks' => $nb_tasks,
);
}
if ($total === 0) {
return array();
}
foreach ($metrics as &$metric) {
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
}
return $metrics;
}
/**
* Get users repartition
*
* @access public
* @param integer $project_id
* @return array
*/
public function getUserRepartition($project_id)
{
$metrics = array();
$total = 0;
$tasks = $this->taskFinder->getAll($project_id);
$users = $this->projectUserRole->getAssignableUsersList($project_id);
foreach ($tasks as $task) {
$user = isset($users[$task['owner_id']]) ? $users[$task['owner_id']] : $users[0];
$total++;
if (! isset($metrics[$user])) {
$metrics[$user] = array(
'nb_tasks' => 0,
'percentage' => 0,
'user' => $user,
);
}
$metrics[$user]['nb_tasks']++;
}
if ($total === 0) {
return array();
}
foreach ($metrics as &$metric) {
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
}
ksort($metrics);
return array_values($metrics);
}
/**
* Get the average lead and cycle time
*
@@ -179,49 +103,4 @@ class ProjectAnalytic extends Base
return $stats;
}
/**
* Get the time spent and estimated into each status
*
* @access public
* @param integer $project_id
* @return array
*/
public function getHoursByStatus($project_id)
{
$stats = array();
// Get the times related to each task
$tasks = $this->db
->table(Task::TABLE)
->columns('id', 'time_estimated', 'time_spent', 'is_active')
->eq('project_id', $project_id)
->desc('id')
->limit(1000)
->findAll();
// Init values
$stats['closed'] = array(
'time_spent' => 0,
'time_estimated' => 0,
);
$stats['open'] = array(
'time_spent' => 0,
'time_estimated' => 0,
);
// Add times spent and estimated to each status
foreach ($tasks as &$task) {
if ($task['is_active']) {
$stats['open']['time_estimated'] += $task['time_estimated'];
$stats['open']['time_spent'] += $task['time_spent'];
} else {
$stats['closed']['time_estimated'] += $task['time_estimated'];
$stats['closed']['time_spent'] += $task['time_spent'];
}
}
return $stats;
}
}

View File

@@ -14,6 +14,11 @@ use Kanboard\Core\Http\Client as HttpClient;
class ClassProvider implements ServiceProviderInterface
{
private $classes = array(
'Analytic' => array(
'TaskDistributionAnalytic',
'UserDistributionAnalytic',
'EstimatedTimeComparisonAnalytic',
),
'Model' => array(
'Action',
'ActionParameter',

View File

@@ -4,8 +4,8 @@
<div class="listing">
<ul>
<li><?= t('Estimated hours: ').'<strong>'.$this->e($metrics['open']['time_estimated']+$metrics['open']['time_estimated']) ?></strong></li>
<li><?= t('Actual hours: ').'<strong>'.$this->e($metrics['open']['time_spent']+$metrics['closed']['time_spent']) ?></strong></li>
<li><?= t('Estimated hours: ').'<strong>'.$this->e($metrics['open']['time_estimated'] + $metrics['closed']['time_estimated']) ?></strong></li>
<li><?= t('Actual hours: ').'<strong>'.$this->e($metrics['open']['time_spent'] + $metrics['closed']['time_spent']) ?></strong></li>
</ul>
</div>
@@ -13,7 +13,12 @@
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
<?php else: ?>
<section id="analytic-compare-hours">
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS)?>' data-label-spent="<?= t('Hours Spent') ?>" data-label-estimated="<?= t('Hours Estimated') ?>"></div>
<div id="chart"
data-metrics='<?= json_encode($metrics, JSON_HEX_APOS)?>'
data-label-spent="<?= t('Hours Spent') ?>"
data-label-estimated="<?= t('Hours Estimated') ?>"
data-label-closed="<?= t('Closed') ?>"
data-label-open="<?= t('Open') ?>"></div>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('No tasks found.') ?></p>