Move analytic logic to separate classes
This commit is contained in:
50
app/Analytic/EstimatedTimeComparisonAnalytic.php
Normal file
50
app/Analytic/EstimatedTimeComparisonAnalytic.php
Normal 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;
|
||||
}
|
||||
}
|
||||
48
app/Analytic/TaskDistributionAnalytic.php
Normal file
48
app/Analytic/TaskDistributionAnalytic.php
Normal 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;
|
||||
}
|
||||
}
|
||||
56
app/Analytic/UserDistributionAnalytic.php
Normal file
56
app/Analytic/UserDistributionAnalytic.php
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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']),
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user