public function getFarmPeriodData($farmId, Scalr_Environment $environment, $mode, $startDate, $endDate)
{
$utcTz = new DateTimeZone('UTC');
$iterator = ChartPeriodIterator::create($mode, new DateTime($startDate, $utcTz), new DateTime($endDate, $utcTz), 'UTC');
$start = $iterator->getStart();
$end = $iterator->getEnd();
$dbFarm = new DBFarm($farmId);
$projectId = $dbFarm->GetSetting('project_id');
//Interval which is used in the database query for grouping
$queryInterval = preg_replace('/^1 /', '', $iterator->getInterval());
$criteria = ['farmId' => $farmId, 'envId' => $environment->id];
//Requests data for the specified period
$rawUsage = $this->getFarmData($environment->clientId, $criteria, $start, $end, [$queryInterval, TagEntity::TAG_ID_FARM_ROLE], true);
//Requests data for the previous period
$rawPrevUsage = $this->getFarmData($environment->clientId, $criteria, $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [$queryInterval, TagEntity::TAG_ID_FARM_ROLE], true);
$usgByInstanceDetailed = (new AggregationCollection(['period', 'farmRoleId'], ['cost' => 'sum']))->load($rawUsage)->calculatePercentage();
$usgByInstancePrevDetailed = (new AggregationCollection(['period', 'farmRoleId'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage();
$quarterIterator = $this->getCurrentQuarterIterator();
$queryQuarterInterval = preg_replace('/^1 /', '', $quarterIterator->getInterval());
$rawQuarterUsage = $this->getFarmData($environment->clientId, $criteria, $quarterIterator->getStart(), $quarterIterator->getEnd(), [TagEntity::TAG_ID_FARM_ROLE], true);
$itemsRollingAvg = $this->getRollingAvg(['farmId' => $farmId], $queryQuarterInterval, $quarterIterator->getEnd(), $environment->clientId, $rawQuarterUsage);
$farmRolesData = [];
$timeline = [];
$prevPointKey = null;
foreach ($iterator as $chartPoint) {
/* @var $chartPoint \Scalr\Stats\CostAnalytics\ChartPointInfo */
$i = $chartPoint->i;
$currentPeriodTotal = isset($usgByInstanceDetailed['data'][$chartPoint->key]) ? $usgByInstanceDetailed['data'][$chartPoint->key] : null;
$ppTotal = isset($usgByInstancePrevDetailed['data'][$chartPoint->previousPeriodKey]) ? $usgByInstancePrevDetailed['data'][$chartPoint->previousPeriodKey] : null;
$pptTotal = isset($usgByInstanceDetailed['data'][$prevPointKey]) ? $usgByInstanceDetailed['data'][$prevPointKey] : null;
$pointDataTotal = $this->getPointDataArray($currentPeriodTotal, $ppTotal, $pptTotal);
$timeline[] = ['datetime' => $chartPoint->dt->format('Y-m-d H:00'), 'label' => $chartPoint->label, 'onchart' => $chartPoint->show, 'events' => null] + $pointDataTotal;
//Period - FarmRoles subtotals
if (!isset($usgByInstanceDetailed['data'][$chartPoint->key]['data'])) {
foreach ($farmRolesData as $farmRoleId => $v) {
if (!$iterator->isFuture()) {
//Previous period details
if (isset($usgByInstancePrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmRoleId])) {
$pp = $usgByInstancePrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmRoleId];
} else {
$pp = null;
}
//Previous point details
if (isset($usgByInstanceDetailed['data'][$prevPointKey]['data'][$farmRoleId])) {
$ppt = $usgByInstanceDetailed['data'][$prevPointKey]['data'][$farmRoleId];
} else {
$ppt = null;
}
$r = $this->getPointDataArray(null, $pp, $ppt);
$farmRolesData[$farmRoleId]['name'] = AccountTagEntity::fetchName($farmRoleId, TagEntity::TAG_ID_FARM_ROLE);
$farmRolesData[$farmRoleId]['data'][] = $r;
} else {
$farmRolesData[$farmRoleId]['data'][] = null;
}
}
} else {
//Initializes with empty values to prevent data shifts on charts.
if (!isset($usgByInstanceDetailed['data'][$chartPoint->key]['data'])) {
$usgByInstanceDetailed['data'][$chartPoint->key]['data'] = [];
}
$combined =& $usgByInstanceDetailed['data'][$chartPoint->key]['data'];
if (!empty($farmRolesData)) {
foreach ($farmRolesData as $farmRoleId => $t) {
if (!array_key_exists($farmRoleId, $combined)) {
$combined[$farmRoleId] = [];
}
}
}
foreach ($combined as $farmRoleId => $v) {
//Previous period details
if (isset($usgByInstancePrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmRoleId])) {
$pp = $usgByInstancePrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmRoleId];
} else {
$pp = null;
}
//Previous point details
if (isset($usgByInstanceDetailed['data'][$prevPointKey]['data'][$farmRoleId])) {
$ppt = $usgByInstanceDetailed['data'][$prevPointKey]['data'][$farmRoleId];
} else {
$ppt = null;
}
if (!isset($farmRolesData[$farmRoleId]) && $i > 0) {
$farmRolesData[$farmRoleId]['name'] = AccountTagEntity::fetchName($farmRoleId, TagEntity::TAG_ID_FARM_ROLE);
$farmRolesData[$farmRoleId]['data'] = array_fill(0, $i, null);
}
if (!$iterator->isFuture()) {
$r = $this->getPointDataArray($v, $pp, $ppt);
$farmRolesData[$farmRoleId]['name'] = AccountTagEntity::fetchName($farmRoleId, TagEntity::TAG_ID_FARM_ROLE);
$farmRolesData[$farmRoleId]['data'][] = $r;
} else {
$farmRolesData[$farmRoleId]['data'][] = null;
}
}
}
$prevPointKey = $chartPoint->key;
}
$cntpoints = count($timeline);
foreach ($farmRolesData as $farmRoleId => $v) {
if (($j = count($v['data'])) < $cntpoints) {
while ($j < $cntpoints) {
$farmRolesData[$farmRoleId]['data'][] = null;
$j++;
}
}
}
//Subtotals by usageItem
$usage = (new AggregationCollection(['farmRoleId' => ['cloudLocation', 'platform']], ['cost' => 'sum']))->load($rawUsage)->calculatePercentage();
//Previous period subtotals by usageItem
$prevUsage = (new AggregationCollection(['farmRoleId'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage();
if ($iterator->getWholePreviousPeriodEnd() != $iterator->getPreviousEnd()) {
$rawPrevUsageWhole = $this->getFarmData($environment->clientId, $criteria, $iterator->getPreviousStart(), $iterator->getWholePreviousPeriodEnd(), [TagEntity::TAG_ID_FARM_ROLE], true);
//Previous whole period usage subtotals by farm role
$prevUsageWhole = (new AggregationCollection(['farmRoleId'], ['cost' => 'sum']))->load($rawPrevUsageWhole);
} else {
$prevUsageWhole = $prevUsage;
}
//Build farm roles total
$farmRolesTotal = [];
$it = $usage->getIterator();
foreach ($it as $farmRoleId => $p) {
$pp = isset($prevUsage['data'][$farmRoleId]) ? $prevUsage['data'][$farmRoleId] : null;
$pw = isset($prevUsageWhole['data'][$farmRoleId]) ? $prevUsageWhole['data'][$farmRoleId] : null;
$frPrev = $this->getTotalDataArray($farmRoleId, AccountTagEntity::fetchName($farmRoleId, TagEntity::TAG_ID_FARM_ROLE), $p, $pp, $pw, $farmRolesData, $iterator);
$frPrev['platform'] = $p['platform'];
$frPrev['cloudLocation'] = $p['cloudLocation'];
$farmRolesTotal[] = $frPrev;
}
//Subtotals by distr types
$usage3 = (new AggregationCollection(['distributionType'], ['cost' => 'sum']))->load($this->getFarmData($environment->clientId, $criteria, $start, $end, ['distributionType', 'usageType', 'usageItem'], true))->calculatePercentage();
// Build cost dist types total
$distributionTypesTotal = [];
foreach ($usage3->getIterator() as $distributionType => $costUsage) {
$distributionTypesTotal[] = $this->getTotalDataArray($distributionType, $distributionType, $costUsage, null, null, [], null, true);
}
$data = ['totals' => ['cost' => round($usage['cost'], 2), 'prevCost' => round($prevUsage['cost'], 2), 'growth' => round($usage['cost'] - $prevUsage['cost'], 2), 'growthPct' => $prevUsage['cost'] == 0 ? null : round(abs(($usage['cost'] - $prevUsage['cost']) / $prevUsage['cost'] * 100), 0), 'farmRoles' => $farmRolesTotal, 'distributionTypes' => $distributionTypesTotal, 'trends' => $this->calculateSpendingTrends(['farmId' => $farmId], $timeline, $queryInterval, $iterator->getEnd(), $environment->clientId), 'forecastCost' => null], 'timeline' => $timeline, 'farmRoles' => $farmRolesData, 'interval' => $queryInterval, 'startDate' => $iterator->getStart()->format('Y-m-d'), 'endDate' => $iterator->getEnd()->format('Y-m-d'), 'previousStartDate' => $iterator->getPreviousStart()->format('Y-m-d'), 'previousEndDate' => $iterator->getPreviousEnd()->format('Y-m-d')];
if ($iterator->getTodayDate() < $iterator->getEnd()) {
//Today is in the selected period
$data['totals']['forecastCost'] = self::calculateForecast($data['totals']['cost'], $start, $end, $prevUsageWhole['cost'], ($data['totals']['growth'] >= 0 ? 1 : -1) * $data['totals']['growthPct'], isset($itemsRollingAvg['rollingAverageDaily']) ? $itemsRollingAvg['rollingAverageDaily'] : null);
}
$budgetRequest = ['projectId' => $projectId, 'usage' => $data['totals']['cost']];
if ($mode != 'custom') {
//We need to get budget for the appropriate quarter
$budgetRequest['period'] = $iterator->getQuarterPeriod();
}
$budget = $this->getBudgetUsedPercentage($budgetRequest);
$this->calculateBudgetEstimateOverspend($budget);
$data['totals']['budget'] = $budget;
return $data;
}