Scalr\Stats\CostAnalytics\Usage::getEnvironmentPeriodData PHP Method

getEnvironmentPeriodData() public method

Gets cost analytics for environment scope
public getEnvironmentPeriodData ( Scalr_Environment $env, string $mode, string $startDate, string $endDate ) : array
$env Scalr_Environment Current environment
$mode string The mode (week, month, quarter, year)
$startDate string The start date of the period in UTC ('Y-m-d')
$endDate string The end date of the period in UTC ('Y-m-d')
return array Returns cost analytics data for environment scope
    public function getEnvironmentPeriodData(Scalr_Environment $env, $mode, $startDate, $endDate)
    {
        $analytics = $this->getContainer()->analytics;
        $utcTz = new DateTimeZone('UTC');
        $iterator = ChartPeriodIterator::create($mode, new DateTime($startDate, $utcTz), new DateTime($endDate, $utcTz), 'UTC');
        $start = $iterator->getStart();
        $end = $iterator->getEnd();
        $timelineEvents = $analytics->events->count($iterator->getInterval(), $iterator->getStart(), $iterator->getEnd(), ['envId' => $env->id, 'accountId' => $env->clientId]);
        //Interval which is used in the database query for grouping
        $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval());
        $criteria = ['envId' => $env->id];
        //Requests data for the specified period
        $rawUsage = $this->getFarmData($env->clientId, $criteria, $start, $end, [$queryInterval, TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true);
        //Requests data for the previous period
        $rawPrevUsage = $this->getFarmData($env->clientId, $criteria, $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [$queryInterval, TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true);
        $max = 5;
        //Calculates top five farms for the specified period
        $top5farms = [];
        $this->otherFarmsQuantity = 0;
        $arr = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawUsage)->getArrayCopy();
        if (!empty($arr['data']) && count($arr['data']) > $max + 1) {
            $this->otherFarmsQuantity = count($arr['data']) - $max;
            uasort($arr['data'], function ($a, $b) {
                if ($a['cost'] == $b['cost']) {
                    return 0;
                }
                return $a['cost'] < $b['cost'] ? 1 : -1;
            });
            $i = 0;
            foreach ($arr['data'] as $farmId => $v) {
                $top5farms[$farmId] = $farmId;
                if (++$i >= 5) {
                    break;
                }
            }
        }
        $usgByPlatformDetailed = (new AggregationCollection(['period', 'platform'], ['cost' => 'sum']))->load($rawUsage)->calculatePercentage();
        $usgByPlatformPrevDetailed = (new AggregationCollection(['period', 'platform'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage();
        if (empty($top5farms)) {
            $usgByFarmDetailed = (new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']))->load($rawUsage)->calculatePercentage();
            $usgByFarmPrevDetailed = (new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage();
        } else {
            $usgByFarmDetailed = new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']);
            foreach ($rawUsage as $d) {
                if (!array_key_exists($d['farmId'], $top5farms)) {
                    $d['farmId'] = self::EVERYTHING_ELSE;
                }
                $usgByFarmDetailed->append($d);
            }
            $usgByFarmDetailed->calculatePercentage();
            $usgByFarmPrevDetailed = new AggregationCollection(['period', 'farmId', 'platform'], ['cost' => 'sum']);
            foreach ($rawPrevUsage as $d) {
                if (!array_key_exists($d['farmId'], $top5farms)) {
                    $d['farmId'] = self::EVERYTHING_ELSE;
                }
                $usgByFarmPrevDetailed->append($d);
            }
            $usgByFarmPrevDetailed->calculatePercentage();
        }
        $quarterIterator = $this->getCurrentQuarterIterator();
        $queryQuarterInterval = preg_replace('/^1 /', '', $quarterIterator->getInterval());
        $rawQuarterUsage = $this->getFarmData($env->clientId, $criteria, $quarterIterator->getStart(), $quarterIterator->getEnd(), [TagEntity::TAG_ID_PLATFORM], true);
        $itemsRollingAvg = $this->getRollingAvg(['envId' => $env->id], $queryQuarterInterval, $quarterIterator->getEnd(), $env->clientId, $rawQuarterUsage, ['platform' => 'clouds']);
        $cloudsData = [];
        $farmsData = [];
        $timeline = [];
        $prevPointKey = null;
        foreach ($iterator as $chartPoint) {
            /* @var $chartPoint \Scalr\Stats\CostAnalytics\ChartPointInfo */
            $i = $chartPoint->i;
            $currentPeriodTotal = isset($usgByPlatformDetailed['data'][$chartPoint->key]) ? $usgByPlatformDetailed['data'][$chartPoint->key] : null;
            $ppTotal = isset($usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]) ? $usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey] : null;
            $pptTotal = isset($usgByPlatformDetailed['data'][$prevPointKey]) ? $usgByPlatformDetailed['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' => isset($timelineEvents[$chartPoint->key]) ? $timelineEvents[$chartPoint->key] : null] + $pointDataTotal;
            //Period - Platform - Farms subtotals
            if (!isset($usgByPlatformDetailed['data'][$chartPoint->key]['data'])) {
                foreach ($cloudsData as $platform => $v) {
                    if (!$iterator->isFuture()) {
                        //Previous period details
                        if (isset($usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform])) {
                            $pp = $usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform];
                        } else {
                            $pp = null;
                        }
                        //Previous point details
                        if (isset($usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform])) {
                            $ppt = $usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform];
                        } else {
                            $ppt = null;
                        }
                        $r = $this->getPointDataArray(null, $pp, $ppt);
                        $cloudsData[$platform]['data'][] = $r;
                    } else {
                        $cloudsData[$platform]['data'][] = null;
                    }
                }
            } else {
                //Initializes with empty values to prevent data shifts on charts.
                if (!isset($usgByPlatformDetailed['data'][$chartPoint->key]['data'])) {
                    $usgByPlatformDetailed['data'][$chartPoint->key]['data'] = [];
                }
                $combined =& $usgByPlatformDetailed['data'][$chartPoint->key]['data'];
                if (!empty($cloudsData)) {
                    foreach ($cloudsData as $platform => $t) {
                        if (!array_key_exists($platform, $combined)) {
                            $combined[$platform] = [];
                        }
                    }
                }
                foreach ($combined as $platform => $v) {
                    //Previous period details
                    if (isset($usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform])) {
                        $pp = $usgByPlatformPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$platform];
                    } else {
                        $pp = null;
                    }
                    //Previous point details
                    if (isset($usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform])) {
                        $ppt = $usgByPlatformDetailed['data'][$prevPointKey]['data'][$platform];
                    } else {
                        $ppt = null;
                    }
                    if (!isset($cloudsData[$platform]) && $i > 0) {
                        $cloudsData[$platform]['name'] = $platform;
                        //initializes platfrorm legend for the not filled period
                        $cloudsData[$platform]['data'] = array_fill(0, $i, null);
                    }
                    if (!$iterator->isFuture()) {
                        $r = $this->getPointDataArray($v, $pp, $ppt);
                        $cloudsData[$platform]['name'] = $platform;
                        $cloudsData[$platform]['data'][] = $r;
                    } else {
                        $cloudsData[$platform]['data'][] = null;
                    }
                }
            }
            //Period - Farm - Platform subtotal
            if (!isset($usgByFarmDetailed['data'][$chartPoint->key]['data'])) {
                foreach ($farmsData as $farmId => $v) {
                    if (!$iterator->isFuture()) {
                        //Previous period details
                        if (isset($usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId])) {
                            $pp = $usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId];
                        } else {
                            $pp = null;
                        }
                        //Previous point details
                        if (isset($usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId])) {
                            $ppt = $usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId];
                        } else {
                            $ppt = null;
                        }
                        $r = $this->getPointDataArray(null, $pp, $ppt);
                        $r['clouds'] = [];
                        $r['usageTypes'] = [];
                        $farmsData[$farmId]['data'][] = $r;
                    } else {
                        $farmsData[$farmId]['data'][] = null;
                    }
                }
            } else {
                //Initializes with empty values to prevent data shifts on charts.
                if (!isset($usgByFarmDetailed['data'][$chartPoint->key]['data'])) {
                    $usgByFarmDetailed['data'][$chartPoint->key]['data'] = [];
                }
                $combined =& $usgByFarmDetailed['data'][$chartPoint->key]['data'];
                if (!empty($farmsData)) {
                    foreach ($farmsData as $farmId => $t) {
                        if (!array_key_exists($farmId, $combined)) {
                            $combined[$farmId] = [];
                        }
                    }
                }
                foreach ($combined as $farmId => $v) {
                    //Previous period details
                    if (isset($usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId])) {
                        $pp = $usgByFarmPrevDetailed['data'][$chartPoint->previousPeriodKey]['data'][$farmId];
                    } else {
                        $pp = null;
                    }
                    //Previous point details
                    if (isset($usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId])) {
                        $ppt = $usgByFarmDetailed['data'][$prevPointKey]['data'][$farmId];
                    } else {
                        $ppt = null;
                    }
                    if (!isset($farmsData[$farmId]) && $i > 0) {
                        $farmsData[$farmId]['name'] = $this->fetchFarmName($farmId);
                        //initializes project legend for the not filled period
                        $farmsData[$farmId]['data'] = array_fill(0, $i, null);
                    }
                    if (!$iterator->isFuture()) {
                        $r = $this->getPointDataArray($v, $pp, $ppt);
                        // platform data
                        $cloudPlatformData = [];
                        if (!empty($v['data'])) {
                            foreach ($v['data'] as $platform => $pv) {
                                $cloudPlatformData[] = $this->getDetailedPointDataArray($platform, $platform, $pv, isset($pp['data'][$platform]) ? $pp['data'][$platform] : null, isset($ppt['data'][$platform]) ? $ppt['data'][$platform] : null);
                            }
                        }
                        $r['clouds'] = $cloudPlatformData;
                        $farmsData[$farmId]['name'] = $this->fetchFarmName($farmId);
                        $farmsData[$farmId]['data'][] = $r;
                    } else {
                        $farmsData[$farmId]['data'][] = null;
                    }
                }
            }
            $prevPointKey = $chartPoint->key;
        }
        //complete arrays for cloud data and farm data
        $cntpoints = count($timeline);
        foreach ($cloudsData as $platform => $v) {
            if (($j = count($v['data'])) < $cntpoints) {
                while ($j < $cntpoints) {
                    $cloudsData[$platform]['data'][] = null;
                    $j++;
                }
            }
        }
        foreach ($farmsData as $farmId => $v) {
            if (($j = count($v['data'])) < $cntpoints) {
                while ($j < $cntpoints) {
                    $farmsData[$farmId]['data'][] = null;
                    $j++;
                }
            }
        }
        //Subtotals by platforms
        $usage = new AggregationCollection(['platform', 'farmId'], ['cost' => 'sum']);
        //Subtotals by farms
        $usage2 = new AggregationCollection(['farmId' => ['projectId', 'envId'], 'platform'], ['cost' => 'sum']);
        //Subtotals by distr types
        $usage3 = (new AggregationCollection(['distributionType'], ['cost' => 'sum']))->load($this->getFarmData($env->clientId, $criteria, $start, $end, ['distributionType', 'usageType', 'usageItem'], true))->calculatePercentage();
        //Previous period subtotals by platforms
        $prevUsage = new AggregationCollection(['platform', 'farmId'], ['cost' => 'sum']);
        //Previous period subtotals by farms
        $prevUsage2 = new AggregationCollection(['farmId', 'platform'], ['cost' => 'sum']);
        if (empty($top5farms)) {
            //Loads current period
            foreach ($rawUsage as $item) {
                $usage->append($item);
                $usage2->append($item);
            }
            //Loads previous period
            foreach ($rawPrevUsage as $item) {
                $prevUsage->append($item);
                $prevUsage2->append($item);
            }
        } else {
            //Loads current period and aggregates top 5 farms
            foreach ($rawUsage as $item) {
                if (!array_key_exists($item['farmId'], $top5farms)) {
                    $item['farmId'] = self::EVERYTHING_ELSE;
                }
                $usage->append($item);
                $usage2->append($item);
            }
            //Loads previous period and aggregates top 5 farms
            foreach ($rawPrevUsage as $item) {
                if (!array_key_exists($item['farmId'], $top5farms)) {
                    $item['farmId'] = self::EVERYTHING_ELSE;
                }
                $prevUsage->append($item);
                $prevUsage2->append($item);
            }
        }
        //Calculates percentage
        $usage->calculatePercentage();
        $usage2->calculatePercentage();
        $prevUsage->calculatePercentage();
        $prevUsage2->calculatePercentage();
        if ($iterator->getWholePreviousPeriodEnd() != $iterator->getPreviousEnd()) {
            $rawPrevUsageWhole = $this->getFarmData($env->clientId, ['envId' => $env->id], $iterator->getPreviousStart(), $iterator->getWholePreviousPeriodEnd(), [TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true);
            //Previous whole period usage subtotals by platform
            $prevUsageWhole = (new AggregationCollection(['platform'], ['cost' => 'sum']))->load($rawPrevUsageWhole);
            //Previous whole period usage subtotals by farm
            $prevUsageWhole2 = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawPrevUsageWhole);
        } else {
            $prevUsageWhole = $prevUsage;
            $prevUsageWhole2 = $prevUsage2;
        }
        //Build cloud platforms total
        $cloudsTotal = [];
        $it = $usage->getIterator();
        foreach ($it as $platform => $p) {
            $pp = isset($prevUsage['data'][$platform]) ? $prevUsage['data'][$platform] : null;
            $pw = isset($prevUsageWhole['data'][$platform]) ? $prevUsageWhole['data'][$platform] : null;
            $cl = $this->getTotalDataArray($platform, $platform, $p, $pp, $pw, $cloudsData, $iterator);
            $cloudsTotal[] = $cl;
        }
        //Build farms total
        $farmsTotal = [];
        $it = $usage2->getIterator();
        foreach ($it as $farmId => $p) {
            $pp = isset($prevUsage2['data'][$farmId]) ? $prevUsage2['data'][$farmId] : null;
            $pw = isset($prevUsageWhole2['data'][$farmId]) ? $prevUsageWhole2['data'][$farmId] : null;
            $cl = $this->getTotalDataArray($farmId, $this->fetchFarmName($farmId), $p, $pp, $pw, $farmsData, $iterator);
            if ($farmId && $farmId != self::EVERYTHING_ELSE) {
                $userId = AccountTagEntity::fetchName($farmId, TagEntity::TAG_ID_FARM_OWNER);
                if ($userId) {
                    $cl['email'] = AccountTagEntity::fetchName($userId, TagEntity::TAG_ID_USER, $env->clientId);
                }
                if (!empty($p['envId'])) {
                    $cl['environment'] = ['id' => (int) $p['envId'], 'name' => AccountTagEntity::fetchName($p['envId'], TagEntity::TAG_ID_ENVIRONMENT)];
                }
                if (!empty($p['projectId']) && $p['projectId'] !== '00000000-0000-0000-0000-000000000000') {
                    $cl['projectName'] = AccountTagEntity::fetchName($p['projectId'], TagEntity::TAG_ID_PROJECT);
                } else {
                    $cl['projectName'] = 'Unassigned resources';
                }
            }
            if ($it->hasChildren()) {
                $clPlatforms = [];
                foreach ($it->getChildren() as $platform => $c) {
                    $cp = isset($prevUsage2['data'][$farmId]['data'][$platform]) ? $prevUsage2['data'][$farmId]['data'][$platform] : null;
                    $clPlatforms[] = $this->getTotalDataArray($platform, $platform, $c, $cp, null, $cloudsData, $iterator, true);
                }
                $cl['clouds'] = $clPlatforms;
            } else {
                $cl['clouds'] = [];
            }
            $farmsTotal[] = $cl;
        }
        // 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), 'clouds' => $cloudsTotal, 'farms' => $farmsTotal, 'distributionTypes' => $distributionTypesTotal, 'trends' => $this->calculateSpendingTrends(['envId' => $env->id], $timeline, $queryInterval, $iterator->getEnd(), $env->clientId), 'forecastCost' => null], 'timeline' => $timeline, 'clouds' => $cloudsData, 'farms' => $farmsData, '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);
        }
        return $data;
    }