diff --git a/app/Foundation/Providers/RepositoryServiceProvider.php b/app/Foundation/Providers/RepositoryServiceProvider.php index 56afc6a16..539ab5864 100644 --- a/app/Foundation/Providers/RepositoryServiceProvider.php +++ b/app/Foundation/Providers/RepositoryServiceProvider.php @@ -13,9 +13,9 @@ namespace CachetHQ\Cachet\Foundation\Providers; use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Repositories\Metric\MetricRepository; -use CachetHQ\Cachet\Repositories\Metric\MySqlRepository as MetricMySqlRepository; -use CachetHQ\Cachet\Repositories\Metric\PgSqlRepository as MetricPgSqlRepository; -use CachetHQ\Cachet\Repositories\Metric\SqliteRepository as MetricSqliteRepository; +use CachetHQ\Cachet\Repositories\Metric\MySqlRepository; +use CachetHQ\Cachet\Repositories\Metric\PgSqlRepository; +use CachetHQ\Cachet\Repositories\Metric\SqliteRepository; use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Contracts\Container\Container; use Illuminate\Support\ServiceProvider; @@ -46,14 +46,11 @@ class RepositoryServiceProvider extends ServiceProvider { $this->app->singleton(MetricRepository::class, function (Container $app) { $config = $app->make(ConfigRepository::class); - $driver = $config->get('database.default'); - if ($driver == 'mysql') { - $repository = new MetricMySqlRepository($config); - } elseif ($driver == 'pgsql') { - $repository = new MetricPgSqlRepository($config); - } elseif ($driver == 'sqlite') { - $repository = new MetricSqliteRepository($config); + switch ($config->get('database.default')) { + case 'mysql': $repository = new MySqlRepository($config); break; + case 'pgsql': $repository = new PgSqlRepository($config); break; + case 'sqlite': $repository = new SqliteRepository($config); break; } $dates = $app->make(DateFactory::class); diff --git a/app/Http/Controllers/StatusPageController.php b/app/Http/Controllers/StatusPageController.php index 5ae8717b1..bf257498c 100644 --- a/app/Http/Controllers/StatusPageController.php +++ b/app/Http/Controllers/StatusPageController.php @@ -31,20 +31,22 @@ use McCool\LaravelAutoPresenter\Facades\AutoPresenter; class StatusPageController extends AbstractApiController { /** + * The metric repository instance. + * * @var \CachetHQ\Cachet\Repositories\Metric\MetricRepository */ - protected $metricRepository; + protected $metrics; /** * Construct a new status page controller instance. * - * @param \CachetHQ\Cachet\Repositories\Metric\MetricRepository $metricRepository + * @param \CachetHQ\Cachet\Repositories\Metric\MetricRepository $metrics * * @return void */ - public function __construct(MetricRepository $metricRepository) + public function __construct(MetricRepository $metrics) { - $this->metricRepository = $metricRepository; + $this->metrics = $metrics; } /** @@ -141,16 +143,16 @@ class StatusPageController extends AbstractApiController switch ($type) { case 'last_hour': - $metricData = $this->metricRepository->listPointsLastHour($metric); + $metricData = $this->metrics->listPointsLastHour($metric); break; case 'today': - $metricData = $this->metricRepository->listPointsToday($metric); + $metricData = $this->metrics->listPointsToday($metric); break; case 'week': - $metricData = $this->metricRepository->listPointsForWeek($metric); + $metricData = $this->metrics->listPointsForWeek($metric); break; case 'month': - $metricData = $this->metricRepository->listPointsForMonth($metric); + $metricData = $this->metrics->listPointsForMonth($metric); break; } diff --git a/app/Presenters/MetricPresenter.php b/app/Presenters/MetricPresenter.php index f980e93d5..3a76abdd9 100644 --- a/app/Presenters/MetricPresenter.php +++ b/app/Presenters/MetricPresenter.php @@ -27,14 +27,10 @@ class MetricPresenter extends BasePresenter implements Arrayable public function view_name() { switch ($this->wrappedObject->default_view) { - case 0: - return 'last_hour'; - case 1: - return 'today'; - case 2: - return 'week'; - case 3: - return 'month'; + case 0: return 'last_hour'; + case 1: return 'today'; + case 2: return 'week'; + case 3: return 'month'; } } @@ -56,14 +52,10 @@ class MetricPresenter extends BasePresenter implements Arrayable public function trans_string_name() { switch ($this->wrappedObject->default_view) { - case 0: - return 'last_hour'; - case 1: - return 'hourly'; - case 2: - return 'weekly'; - case 3: - return 'monthly'; + case 0: return 'last_hour'; + case 1: return 'hourly'; + case 2: return 'weekly'; + case 3: return 'monthly'; } } diff --git a/app/Repositories/Metric/AbstractMetricRepository.php b/app/Repositories/Metric/AbstractMetricRepository.php index c781d281a..1cd8c985e 100644 --- a/app/Repositories/Metric/AbstractMetricRepository.php +++ b/app/Repositories/Metric/AbstractMetricRepository.php @@ -13,6 +13,7 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; use Illuminate\Contracts\Config\Repository; +use Illuminate\Support\Collection; /** * This is the abstract metric repository class. @@ -52,7 +53,7 @@ abstract class AbstractMetricRepository * * @return string */ - protected function getTableName() + protected function getMetricsTable() { $driver = $this->config->get('database.default'); $connection = $this->config->get('database.connections.'.$driver); @@ -60,4 +61,63 @@ abstract class AbstractMetricRepository return $prefix.'metrics'; } + + /** + * Get the metric points table name. + * + * @return string + */ + protected function getMetricPointsTable() + { + $driver = $this->config->get('database.default'); + $connection = $this->config->get('database.connections.'.$driver); + $prefix = $connection['prefix']; + + return $prefix.'metric_points'; + } + + /** + * Return the query type. + * + * @param \CachetHQ\Cachet\Models\Metric $metric + * + * @return string + */ + protected function getQueryType(Metric $metric) + { + if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { + return "sum({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value"; + } elseif ($metric->calc_type == Metric::CALC_AVG) { + return "avg({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value"; + } else { + return "sum({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value"; + } + } + + /** + * Map the result set. + * + * @param \CachetHQ\Cachet\Models\Metric $metric + * @param array $results + * + * @return \Illuminate\Support\Collection + */ + protected function mapResults(Metric $metric, array $results) + { + $results = Collection::make($results); + + return $results->map(function ($point) use ($metric) { + if (!$point->value) { + $point->value = $metric->default_value; + } + + if ($point->value === 0 && $metric->default_value != $value) { + $point->value = $metric->default_value; + } + + $point->value = round($point->value, $metric->places); + + return $point; + }); + } } diff --git a/app/Repositories/Metric/MetricInterface.php b/app/Repositories/Metric/MetricInterface.php index b355192f4..ec0cb1634 100644 --- a/app/Repositories/Metric/MetricInterface.php +++ b/app/Repositories/Metric/MetricInterface.php @@ -13,36 +13,40 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; +/** + * This is the metric interface. + * + * @author James Brooks + */ interface MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute); + public function getPointsSinceMinutes(Metric $metric, $minutes); /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour); + public function getPointsSinceHour(Metric $metric, $hour); /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day); + public function getPointsSinceDay(Metric $metric, $day); } diff --git a/app/Repositories/Metric/MetricRepository.php b/app/Repositories/Metric/MetricRepository.php index 315ffc6e2..7da85f288 100644 --- a/app/Repositories/Metric/MetricRepository.php +++ b/app/Repositories/Metric/MetricRepository.php @@ -15,6 +15,11 @@ use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Models\Metric; use DateInterval; +/** + * This is the metric repository class. + * + * @author James Brooks + */ class MetricRepository { /** @@ -50,22 +55,25 @@ class MetricRepository * * @param \CachetHQ\Cachet\Models\Metric $metric * - * @return array + * @return \Illuminate\Support\Collection */ public function listPointsLastHour(Metric $metric) { $dateTime = $this->dates->make(); - - $points = []; - $pointKey = $dateTime->format('H:i'); + $points = $this->repository->getPointsSinceMinutes($metric, 60)->pluck('value', 'key'); for ($i = 0; $i <= 60; $i++) { - $points[$pointKey] = $this->repository->getPointsLastHour($metric, 0, $i); + if (!$points->has($pointKey)) { + $points->put($pointKey, $metric->default_value); + } + $pointKey = $dateTime->sub(new DateInterval('PT1M'))->format('H:i'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) use ($points) { + return $key; + }); } /** @@ -79,17 +87,20 @@ class MetricRepository public function listPointsToday(Metric $metric, $hours = 12) { $dateTime = $this->dates->make(); - - $points = []; - $pointKey = $dateTime->format('H:00'); + $points = $this->repository->getPointsSinceHour($metric, $hours)->pluck('value', 'key'); for ($i = 0; $i <= $hours; $i++) { - $points[$pointKey] = $this->repository->getPointsByHour($metric, $i); + if (!$points->has($pointKey)) { + $points->put($pointKey, $metric->default_value); + } + $pointKey = $dateTime->sub(new DateInterval('PT1H'))->format('H:00'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) use ($points) { + return $key; + }); } /** @@ -102,17 +113,20 @@ class MetricRepository public function listPointsForWeek(Metric $metric) { $dateTime = $this->dates->make(); - - $points = []; - - $pointKey = $dateTime->format('D jS M'); + $pointKey = $dateTime->format('Y-m-d'); + $points = $this->repository->getPointsSinceDay($metric, 7)->pluck('value', 'key'); for ($i = 0; $i <= 7; $i++) { - $points[$pointKey] = $this->repository->getPointsForDayInWeek($metric, $i); - $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('D jS M'); + if (!$points->has($pointKey)) { + $points->put($pointKey, $metric->default_value); + } + + $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('Y-m-d'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) use ($points) { + return $key; + }); } /** @@ -125,18 +139,20 @@ class MetricRepository public function listPointsForMonth(Metric $metric) { $dateTime = $this->dates->make(); - + $pointKey = $dateTime->format('Y-m-d'); $daysInMonth = $dateTime->format('t'); - - $points = []; - - $pointKey = $dateTime->format('jS M'); + $points = $this->repository->getPointsSinceDay($metric, $daysInMonth)->pluck('value', 'key'); for ($i = 0; $i <= $daysInMonth; $i++) { - $points[$pointKey] = $this->repository->getPointsForDayInWeek($metric, $i); - $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('jS M'); + if (!$points->has($pointKey)) { + $points->put($pointKey, $metric->default_value); + } + + $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('Y-m-d'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) use ($points) { + return $key; + }); } } diff --git a/app/Repositories/Metric/MySqlRepository.php b/app/Repositories/Metric/MySqlRepository.php index a9cca0861..a9b007727 100644 --- a/app/Repositories/Metric/MySqlRepository.php +++ b/app/Repositories/Metric/MySqlRepository.php @@ -12,9 +12,7 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; -use DateInterval; use Illuminate\Support\Facades\DB; -use Jenssegers\Date\Date; /** * This is the mysql repository class. @@ -24,112 +22,59 @@ use Jenssegers\Date\Date; class MySqlRepository extends AbstractMetricRepository implements MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute) + public function getPointsSinceMinutes(Metric $metric, $minutes) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); - $timeInterval = $dateTime->format('YmdHi'); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`'; - } - - $value = 0; - - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H%i') = :timeInterval GROUP BY HOUR(mp.`created_at`), MINUTE(mp.`created_at`)", [ - 'metricId' => $metric->id, - 'timeInterval' => $timeInterval, + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%H:%i') AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :minutes MINUTE) GROUP BY HOUR({$this->getMetricPointsTable()}.`created_at`), MINUTE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + 'minutes' => $minutes, ]); - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour) + public function getPointsSinceHour(Metric $metric, $hour) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); - $hourInterval = $dateTime->format('YmdH'); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`'; - } - - $value = 0; - - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H') = :hourInterval GROUP BY HOUR(mp.`created_at`)", [ - 'metricId' => $metric->id, - 'hourInterval' => $hourInterval, + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%H:00') AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :hour HOUR) GROUP BY HOUR({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + 'hour' => $hour, ]); - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric + * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day) + public function getPointsSinceDay(Metric $metric, $day) { - $dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`'; - } - - $value = 0; - - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.`created_at` BETWEEN DATE_SUB(mp.`created_at`, INTERVAL 1 WEEK) AND DATE_ADD(NOW(), INTERVAL 1 DAY) AND DATE_FORMAT(mp.`created_at`, '%Y%m%d') = :timeInterval GROUP BY DATE_FORMAT(mp.`created_at`, '%Y%m%d')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('Ymd'), + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%Y-%m-%d') AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :day DAY) GROUP BY DATE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + 'day' => $day, ]); - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } } diff --git a/app/Repositories/Metric/PgSqlRepository.php b/app/Repositories/Metric/PgSqlRepository.php index 739c543b0..64d6d4f54 100644 --- a/app/Repositories/Metric/PgSqlRepository.php +++ b/app/Repositories/Metric/PgSqlRepository.php @@ -12,7 +12,6 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; -use DateInterval; use Illuminate\Support\Facades\DB; use Jenssegers\Date\Date; @@ -24,113 +23,56 @@ use Jenssegers\Date\Date; class PgSqlRepository extends AbstractMetricRepository implements MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute) + public function getPointsSinceMinutes(Metric $metric, $minutes) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND to_char(metric_points.created_at, 'YYYYMMDDHH24MI') = :timeInterval GROUP BY to_char(metric_points.created_at, 'HHMI')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdHi'), + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT to_char({$this->getMetricPointsTable()}.created_at, 'HH24:MI') AS key, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.created_at >= (NOW() - INTERVAL '{$minutes}' MINUTE) GROUP BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:MI') ORDER BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:MI')", [ + 'metricId' => $metric->id, ]); - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour) + public function getPointsSinceHour(Metric $metric, $hour) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE metric_points.metric_id = :metricId AND to_char(metric_points.created_at, 'YYYYMMDDHH24') = :timeInterval GROUP BY to_char(metric_points.created_at, 'H')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdH'), + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT to_char({$this->getMetricPointsTable()}.created_at, 'HH24:00') AS key, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.created_at >= (NOW() - INTERVAL '{$hour}' HOUR) GROUP BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:00') ORDER BY to_char({$this->getMetricPointsTable()}.created_at, 'HH24:00')", [ + 'metricId' => $metric->id, ]); - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric + * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day) + public function getPointsSinceDay(Metric $metric, $day) { - $dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(mp.value * mp.counter) AS value'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(mp.value * mp.counter) AS value'; - } - - $value = 0; - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.created_at BETWEEN (mp.created_at - interval '1 week') AND (now() + interval '1 day') AND to_char(mp.created_at, 'YYYYMMDD') = :timeInterval GROUP BY to_char(mp.created_at, 'YYYYMMDD')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('Ymd'), + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT DATE({$this->getMetricPointsTable()}.created_at) AS key, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.created_at >= (DATE(NOW()) - INTERVAL '{$day}' DAY) GROUP BY DATE({$this->getMetricPointsTable()}.created_at) ORDER BY DATE({$this->getMetricPointsTable()}.created_at)", [ + 'metricId' => $metric->id, ]); - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } } diff --git a/app/Repositories/Metric/SqliteRepository.php b/app/Repositories/Metric/SqliteRepository.php index 403d77611..e16ffea84 100644 --- a/app/Repositories/Metric/SqliteRepository.php +++ b/app/Repositories/Metric/SqliteRepository.php @@ -12,123 +12,67 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; -use DateInterval; use Illuminate\Support\Facades\DB; use Jenssegers\Date\Date; +/** + * This is the sqlite repository class. + * + * @author James Brooks + */ class SqliteRepository extends AbstractMetricRepository implements MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute) + public function getPointsSinceMinutes(Metric $metric, $minutes) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H%M', metric_points.created_at) = :timeInterval GROUP BY strftime('%H%M', metric_points.created_at)", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdHi'), + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT strftime('%H:%M', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', '-{$minutes} minutes') GROUP BY strftime('%H', {$this->getMetricPointsTable()}.`created_at`), strftime('%M', {$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, ]); - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour) + public function getPointsSinceHour(Metric $metric, $hour) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H', metric_points.created_at) = :timeInterval GROUP BY strftime('%H', metric_points.created_at)", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdH'), + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT strftime('%H:00', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', '-{$hour} hours') GROUP BY strftime('%H', {$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, ]); - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric + * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day) + public function getPointsSinceDay(Metric $metric, $day) { - $dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND metric_points.created_at > date('now', '-7 day') AND strftime('%Y%m%d', metric_points.created_at) = :timeInterval GROUP BY strftime('%Y%m%d', metric_points.created_at)", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('Ymd'), + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT strftime('%Y-%m-%d', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON metrics.id = {$this->getMetricPointsTable()}.metric_id WHERE metrics.id = :metricId AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', '-{$day} days') GROUP BY DATE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, ]); - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + return $this->mapResults($metric, $points); } }