/** * Gets period data for top farms * * @param int $accountId The current client id * @param array $allowedEnvs Array of allowed environments' ids for current user * @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') * @param int $farmCount Top farms count * @return array Returns cost analytics data for environment scope */ public function getTopFarmsPeriodData($accountId, array $allowedEnvs, $mode, $startDate, $endDate, $farmCount = 5) { $utcTz = new DateTimeZone('UTC'); $iterator = ChartPeriodIterator::create($mode, new DateTime($startDate, $utcTz), new DateTime($endDate, $utcTz), 'UTC'); $start = $iterator->getStart(); $end = $iterator->getEnd(); //Interval which is used in the database query for grouping $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval()); $criteria = !empty($allowedEnvs) ? ['envId' => $allowedEnvs] : []; //Requests data for the specified period $rawUsage = $this->getFarmData($accountId, $criteria, $start, $end, [$queryInterval, TagEntity::TAG_ID_FARM], true); //Requests data for the previous period $rawPrevUsage = $this->getFarmData($accountId, $criteria, $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [$queryInterval, TagEntity::TAG_ID_FARM], true); //Calculates top five farms for the specified period $topFarms = []; $arr = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawUsage)->getArrayCopy(); if (!empty($arr['data']) && count($arr['data']) > $farmCount + 1) { 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) { $topFarms[$farmId] = $farmId; if (++$i >= $farmCount) { break; } } } //Subtotals by farms $usage = new AggregationCollection(['farmId'], ['cost' => 'sum']); //Previous period subtotals by farms $prevUsage = new AggregationCollection(['farmId'], ['cost' => 'sum']); if (empty($topFarms)) { //Loads current period foreach ($rawUsage as $item) { $usage->append($item); } //Loads previous period foreach ($rawPrevUsage as $item) { $prevUsage->append($item); } } else { //Loads current period and aggregates top 5 farms foreach ($rawUsage as $item) { if (array_key_exists($item['farmId'], $topFarms)) { $usage->append($item); } } //Loads previous period and aggregates top 5 farms foreach ($rawPrevUsage as $item) { if (array_key_exists($item['farmId'], $topFarms)) { $prevUsage->append($item); } } } //Calculates percentage $usage->calculatePercentage(); if ($iterator->getWholePreviousPeriodEnd() != $iterator->getPreviousEnd()) { $rawPrevUsageWhole = $this->getFarmData($accountId, ['envId' => $allowedEnvs], $iterator->getPreviousStart(), $iterator->getWholePreviousPeriodEnd(), [TagEntity::TAG_ID_FARM], true); //Previous whole period usage subtotals by farm $prevUsageWhole = (new AggregationCollection(['farmId'], ['cost' => 'sum']))->load($rawPrevUsageWhole); } else { $prevUsageWhole = $prevUsage; } //Build farms total $farmsTotal = []; $it = $usage->getIterator(); foreach ($it as $farmId => $p) { $pp = isset($prevUsage['data'][$farmId]) ? $prevUsage['data'][$farmId] : null; $pw = isset($prevUsageWhole['data'][$farmId]) ? $prevUsageWhole['data'][$farmId] : null; $cl = $this->getTotalDataArray($farmId, $this->fetchFarmName($farmId), $p, $pp, $pw, [], null, true); $farmsTotal[] = $cl; } return $farmsTotal; }
/** * 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]; }