db->transaction(function($db) use ($project_id, $date) { $column_ids = $db->table(Board::TABLE)->eq('project_id', $project_id)->findAllByColumn('id'); foreach ($column_ids as $column_id) { // This call will fail if the record already exists // (cross database driver hack for INSERT..ON DUPLICATE KEY UPDATE) $db->table(ProjectDailyColumnStats::TABLE)->insert(array( 'day' => $date, 'project_id' => $project_id, 'column_id' => $column_id, 'total' => 0, 'score' => 0, )); $db->table(ProjectDailyColumnStats::TABLE) ->eq('project_id', $project_id) ->eq('column_id', $column_id) ->eq('day', $date) ->update(array( 'score' => $db->table(Task::TABLE) ->eq('project_id', $project_id) ->eq('column_id', $column_id) ->eq('is_active', Task::STATUS_OPEN) ->sum('score'), 'total' => $db->table(Task::TABLE) ->eq('project_id', $project_id) ->eq('column_id', $column_id) ->count() )); } }); } /** * Count the number of recorded days for the data range * * @access public * @param integer $project_id Project id * @param string $from Start date (ISO format YYYY-MM-DD) * @param string $to End date * @return integer */ public function countDays($project_id, $from, $to) { $rq = $this->db->execute( 'SELECT COUNT(DISTINCT day) FROM '.self::TABLE.' WHERE day >= ? AND day <= ? AND project_id=?', array($from, $to, $project_id) ); return $rq !== false ? $rq->fetchColumn(0) : 0; } /** * Get raw metrics for the project within a data range * * @access public * @param integer $project_id Project id * @param string $from Start date (ISO format YYYY-MM-DD) * @param string $to End date * @return array */ public function getRawMetrics($project_id, $from, $to) { return $this->db->table(ProjectDailyColumnStats::TABLE) ->columns( ProjectDailyColumnStats::TABLE.'.column_id', ProjectDailyColumnStats::TABLE.'.day', ProjectDailyColumnStats::TABLE.'.total', ProjectDailyColumnStats::TABLE.'.score', Board::TABLE.'.title AS column_title' ) ->join(Board::TABLE, 'id', 'column_id') ->eq(ProjectDailyColumnStats::TABLE.'.project_id', $project_id) ->gte('day', $from) ->lte('day', $to) ->asc(ProjectDailyColumnStats::TABLE.'.day') ->findAll(); } /** * Get raw metrics for the project within a data range grouped by day * * @access public * @param integer $project_id Project id * @param string $from Start date (ISO format YYYY-MM-DD) * @param string $to End date * @return array */ public function getRawMetricsByDay($project_id, $from, $to) { return $this->db->table(ProjectDailyColumnStats::TABLE) ->columns( ProjectDailyColumnStats::TABLE.'.day', 'SUM('.ProjectDailyColumnStats::TABLE.'.total) AS total', 'SUM('.ProjectDailyColumnStats::TABLE.'.score) AS score' ) ->eq(ProjectDailyColumnStats::TABLE.'.project_id', $project_id) ->gte('day', $from) ->lte('day', $to) ->asc(ProjectDailyColumnStats::TABLE.'.day') ->groupBy(ProjectDailyColumnStats::TABLE.'.day') ->findAll(); } /** * Get aggregated metrics for the project within a data range * * [ * ['Date', 'Column1', 'Column2'], * ['2014-11-16', 2, 5], * ['2014-11-17', 20, 15], * ] * * @access public * @param integer $project_id Project id * @param string $from Start date (ISO format YYYY-MM-DD) * @param string $to End date * @param string $column Column to aggregate * @return array */ public function getAggregatedMetrics($project_id, $from, $to, $column = 'total') { $columns = $this->board->getColumnsList($project_id); $column_ids = array_keys($columns); $metrics = array(array_merge(array(e('Date')), array_values($columns))); $aggregates = array(); // Fetch metrics for the project $records = $this->db->table(ProjectDailyColumnStats::TABLE) ->eq('project_id', $project_id) ->gte('day', $from) ->lte('day', $to) ->findAll(); // Aggregate by day foreach ($records as $record) { if (! isset($aggregates[$record['day']])) { $aggregates[$record['day']] = array($record['day']); } $aggregates[$record['day']][$record['column_id']] = $record[$column]; } // Aggregate by row foreach ($aggregates as $aggregate) { $row = array($aggregate[0]); foreach ($column_ids as $column_id) { $row[] = (int) $aggregate[$column_id]; } $metrics[] = $row; } return $metrics; } }