/** * Constructor * * @param \Scalr_Environment $env The environment * @param string $ccId The identifier of the cost center which is assigned * @param string $oldCcId The identifier of the old cost center which is replaced */ public function __construct(Scalr_Environment $env, $ccId, $oldCcId) { parent::__construct(); array_push($this->ccs, $ccId, $oldCcId); $ccName = AccountTagEntity::fetchName($ccId, TagEntity::TAG_ID_COST_CENTRE); $oldCcName = AccountTagEntity::fetchName($oldCcId, TagEntity::TAG_ID_COST_CENTRE); $this->message = sprintf("User %s replaced cost center '%s' with '%s' in the enviroment '%s' id:%d", strip_tags($this->getUserEmail()), strip_tags($oldCcName), strip_tags($ccName), strip_tags($env->name), $env->id); $this->messageToHash = sprintf('%s|%s|%s|%s|%s', $this->timelineEvent->dtime->format('Y-m-d'), $oldCcId, $ccId, $env->id, $this->getUserEmail()); }
/** * Constructor * * @param \DBFarm $farm The DBFarm instance * @param string $projectId The uuid of the project */ public function __construct(DBFarm $farm, $projectId) { parent::__construct(); $projectEntity = ProjectEntity::findPk($projectId); $this->projects[] = $projectId; if ($projectEntity) { $this->ccs[] = $projectEntity->ccId; $projectName = $projectEntity->name; } else { $projectName = AccountTagEntity::fetchName($projectId, TagEntity::TAG_ID_PROJECT); } $this->message = sprintf("User %s assigned a new farm '%s' id:%d to the project '%s'", strip_tags($this->getUserEmail()), strip_tags($farm->Name), $farm->ID, strip_tags($projectName)); $this->messageToHash = sprintf('%s|%s|%s|%s', $this->timelineEvent->dtime->format('Y-m-d'), $this->getUserEmail(), $farm->ID, $projectId); }
/** * Constructor * * @param \DBFarm $farm The DBFarm instance * @param string $projectId The identifier of the project to assign * @param string $oldProjectId The identifier of the old project which is replaced */ public function __construct(DBFarm $farm, $projectId, $oldProjectId) { parent::__construct(); array_push($this->projects, $projectId, $oldProjectId); $projectEntity = ProjectEntity::findPk($projectId); if ($projectEntity) { $this->ccs[$projectEntity->ccId] = $projectEntity->ccId; $projectName = $projectEntity->name; } else { $projectName = AccountTagEntity::fetchName($projectId, TagEntity::TAG_ID_PROJECT); } $oldProjectEntity = ProjectEntity::findPk($oldProjectId); if ($oldProjectEntity) { $this->ccs[$oldProjectEntity->ccId] = $oldProjectEntity->ccId; $oldProjectName = $oldProjectEntity->name; } else { $oldProjectName = AccountTagEntity::fetchName($oldProjectId, TagEntity::TAG_ID_PROJECT); } $this->message = sprintf("User %s replaced project '%s' with project '%s' in the farm '%s' id:%d", strip_tags($this->getUserEmail()), strip_tags($oldProjectName), strip_tags($projectName), strip_tags($farm->Name), $farm->ID); $this->messageToHash = sprintf('%s|%s|%s|%s|%s', $this->timelineEvent->dtime->format('Y-m-d'), $this->getUserEmail(), $oldProjectId, $projectId, $farm->ID); }
/** * Gets farm role with top cost * * @param array $farmRoles Array of farm roles * @return array Returns farm role top spender */ private function getFarmRoleTopSpender(array $farmRoles) { $max = 0; foreach ($farmRoles as $farmRoleId => $farmRole) { if ($max <= $farmRole['cost']) { $max = $farmRole['cost']; $maxId = $farmRoleId; } } $result = ['id' => $maxId, 'alias' => AccountTagEntity::fetchName($maxId, TagEntity::TAG_ID_FARM_ROLE), 'periodTotal' => $farmRoles[$maxId]['cost'], 'platform' => key($farmRoles[$maxId]['data'])]; return $result; }
/** * Synchronizes the account level tag value * * It does not verify itself whether the cost analytics service is enabled * * @param int $accountId The identifier of the client's account * @param int $tagId The identifier of the clould analytics tag * @param string $valueId The identifier of the tag's value * @param string $valueName The name of the tag's value */ public function syncValue($accountId, $tagId, $valueId, $valueName) { if ($accountId === null) { $accountId = 0; } $tag = AccountTagEntity::findPk($accountId, $tagId, $valueId); if (!$tag instanceof AccountTagEntity) { $tag = new AccountTagEntity(); $tag->accountId = $accountId; $tag->tagId = $tagId; $tag->valueId = $valueId; $tag->valueName = $valueName; } else { if ($tag->valueName != $valueName) { $tag->valueName = $valueName; if ($tagId == TagEntity::TAG_ID_FARM) { foreach ($this->db->GetAll("\n SELECT fr.id AS farm_role_id, fr.alias\n FROM farm_roles fr\n WHERE fr.farmid = ?\n ", [$valueId]) as $v) { //Updates all related farm roles $this->syncValue($accountId, TagEntity::TAG_ID_FARM_ROLE, $v['farm_role_id'], sprintf('%s', $v['alias'])); } } } else { $ignoreupdate = true; } } if (!isset($ignoreupdate)) { $tag->save(); } }
/** * Gets cost analytics for environment scope * * @param Scalr_Environment $env Current environment * @param string $mode The mode (week, month, quarter, year) * @param string $startDate The start date of the period in UTC ('Y-m-d') * @param string $endDate 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; }
/** * Gets detailed top 5 usage by farms for specified project on date * * @param string|null $projectId The identifier of the project * @param string $platform The cloud platform * @param string $mode The mode * @param string $date The UTC date within period ('Y-m-d H:00') * @param string $start The start date of the period in UTC ('Y-m-d') * @param string $end The end date of the period in UTC ('Y-m-d') * @param string $ccId optional The identifier of the cost center (It is used only when project is null) * @return array Returns detailed top 5 usage by farms for specified project on date * @throws AnalyticsException * @throws OutOfBoundsException */ public function getProjectFarmsTopUsageOnDate($projectId, $platform, $mode, $date, $start, $end, $ccId = null) { $projectId = empty($projectId) ? null : $projectId; $iterator = new ChartPeriodIterator($mode, $start, $end ?: null, 'UTC'); //Interval which is used in the database query for grouping $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval()); if ($projectId !== null) { $project = ProjectEntity::findPk($projectId); if ($project === null) { if (empty($ccId)) { throw new AnalyticsException(sprintf("Project %s does not exist. Please provide ccId.", $projectId)); } } else { $ccId = $project->ccId; } } //Requests data for the specified period $rawUsage = $this->get(['projectId' => $projectId], $iterator->getStart(), $iterator->getEnd(), [$queryInterval, TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true); //Requests data for the previous period $rawPrevUsage = $this->get(['projectId' => $projectId], $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [$queryInterval, TagEntity::TAG_ID_PLATFORM, TagEntity::TAG_ID_FARM], true); //We do not need to calculate the percentage here $usg = (new AggregationCollection(['period', 'platform', 'farmId' => ['envId']], ['cost' => 'sum']))->load($rawUsage); $prevUsg = (new AggregationCollection(['period', 'platform', 'farmId'], ['cost' => 'sum']))->load($rawPrevUsage)->calculatePercentage(); //Previous chart point $prevcp = null; //Finds the key for current label foreach ($iterator as $chartPoint) { //FIXME rewrite search a point if ($chartPoint->dt->format('Y-m-d H:00') !== $date) { $prevcp = $chartPoint; continue; } $cp = $chartPoint; break; } if (!isset($cp)) { throw new OutOfRangeException(sprintf('Requested date (%s) is out of the range. Last point date is %s', $date, isset($prevcp->dt) ? $prevcp->dt->format('Y-m-d H:00') : 'undefined')); } $result = []; //Maximum number of the farms without grouping $max = 5; $sEverything = self::EVERYTHING_ELSE; if (!empty($usg['data'][$cp->key]['data'][$platform]['data'])) { $usgFarms = new AggregationCollection(['farmId' => ['envId']], ['cost' => 'sum']); $ptr = $usg['data'][$cp->key]['data'][$platform]['data']; uasort($ptr, function ($a, $b) { if ($a['cost'] == $b['cost']) { return 0; } return $a['cost'] > $b['cost'] ? -1 : 1; }); //Aggregates farms if its number more then max + 1 if (count($ptr) > $max + 1) { $this->otherFarmsQuantity = count($ptr) - $max; $new = []; $i = 0; foreach ($ptr as $farmId => $v) { $v['cost_percentage'] = round($usg['data'][$cp->key]['data'][$platform]['cost'] == 0 ? 0 : $v['cost'] * 100 / $usg['data'][$cp->key]['data'][$platform]['cost'], 0); if ($i < $max) { $new[$farmId] = $v; } elseif (!isset($new[self::EVERYTHING_ELSE])) { $v['id'] = self::EVERYTHING_ELSE; $new[self::EVERYTHING_ELSE] = $v; } else { $new[self::EVERYTHING_ELSE]['cost'] += $v['cost']; } $i++; } $new[self::EVERYTHING_ELSE]['cost_percentage'] = round($usg['data'][$cp->key]['data'][$platform]['cost'] == 0 ? 0 : $new[self::EVERYTHING_ELSE]['cost'] * 100 / $usg['data'][$cp->key]['data'][$platform]['cost'], 0); $usgFarms->setArray(['data' => $new]); } else { $usgFarms->setArray($usg['data'][$cp->key]['data'][$platform])->calculatePercentage(); } //Forms result data array foreach ($usgFarms->getIterator() as $farmId => $pv) { $record = $this->getDetailedPointDataArray($farmId, $this->fetchFarmName($farmId), $pv, isset($prevUsg['data'][$cp->previousPeriodKey]['data'][$platform]['data'][$farmId]) ? $prevUsg['data'][$cp->previousPeriodKey]['data'][$platform]['data'][$farmId] : null, isset($usg['data'][$cp->key]['data'][$platform]['data'][$farmId]) ? $usg['data'][$cp->key]['data'][$platform]['data'][$farmId] : null); if ($farmId && $farmId != self::EVERYTHING_ELSE && !empty($pv['envId'])) { $record['environment'] = ['id' => (int) $pv['envId'], 'name' => AccountTagEntity::fetchName($pv['envId'], TagEntity::TAG_ID_ENVIRONMENT)]; } $result[] = $record; } } return ['data' => $result]; }
/** * Gets farm with top cost * * @param array $farms Array of farm roles * @return array Returns farm top spender */ private function getFarmTopSpender(array $farms) { $max = 0; foreach ($farms as $farmId => $farm) { if ($max <= $farm['cost']) { $max = $farm['cost']; $maxId = $farmId; } } $result = ['id' => $maxId, 'name' => AccountTagEntity::fetchName($maxId, TagEntity::TAG_ID_FARM), 'periodTotal' => $farms[$maxId]['cost']]; return $result; }