PluginProbe
Metricool – Social media and site statistics / trunk
Metricool – Social media and site statistics vtrunk
2.1.0 2.0.2 2.0.1 2.0.0 1.27 trunk
metricool / app / Services / Analytics / TrendService.php

TrendService.php in Metricool – Social media and site statistics trunk, at app/Services/Analytics/TrendService.php

126 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Metricool\Services\Analytics;
6
7 use Metricool\Vendor\Carbon\Carbon;
8 use Metricool\Support\Helpers\Collection;
9 use Metricool\Http\Metricool\Entities\TimelineStatistics;
10
11 class TrendService
12 {
13 public const TREND_UP = 'up';
14 public const TREND_DOWN = 'down';
15 public const TREND_STABLE = 'stable';
16
17 /**
18 * Method returns the trend for the given statistic module based on the
19 * given filters. To be able to calculate the trend the filters need
20 * at least a start and an end date in Ymd format. Otherwise, a
21 * 'stable' trend is returned
22 *
23 * @param array $filters Optional filters to override the filters used on
24 * the TimelineStatistics instance. Must contain 'start' and 'end' keys
25 * in Ymd format.
26 */
27 public function getTrend(TimelineStatistics $statistic, Collection $currentStatistics, array $filters = []): string
28 {
29 $cacheName = get_class($statistic) . ':' . $statistic->getMetric() . '#' . md5(json_encode($filters));
30 $cacheValue = wp_cache_get($cacheName, 'metricool', false, $found);
31 if ($found && is_string($cacheValue)) {
32 return $cacheValue;
33 }
34
35 try {
36 $filters = $this->getCurrentPeriodFilters($filters, $statistic);
37 $previousStatistics = $statistic->filter(
38 $this->getPreviousPeriodFilters($filters)
39 )->get();
40 } catch (\Throwable $e) {
41 return self::TREND_STABLE;
42 }
43
44 $trend = $this->calculateTrendFromPeriods($currentStatistics, $previousStatistics);
45
46 wp_cache_set($cacheName, $trend, 'metricool', (5 * MINUTE_IN_SECONDS));
47 return $trend;
48 }
49
50 /**
51 * Method returns filters for the previous period based on the given
52 * filters. A period is defined as the difference between start and
53 * end date.
54 *
55 * @param array $filters Must contain 'start' and 'end' keys and should
56 * reflect the current period to calculate the previous period from.
57 *
58 * @throws \InvalidArgumentException When start or end filters are missing
59 */
60 public function getPreviousPeriodFilters(array $filters): array
61 {
62 if (empty($filters) || empty($filters['start']) || empty($filters['end'])) {
63 throw new \InvalidArgumentException("Filters 'start' and 'end' are required to get the previous period");
64 }
65
66 $start = Carbon::createFromFormat('Ymd', $filters['start']);
67 $end = Carbon::createFromFormat('Ymd', $filters['end']);
68 $diffInDays = $start->diffInDays($end);
69
70 // Previous end is one day before current start
71 $previousEnd = $start->copy()->subDay();
72 $previousStart = $previousEnd->copy()->subDays($diffInDays);
73
74 return [
75 'start' => $previousStart->format('Ymd'),
76 'end' => $previousEnd->format('Ymd'),
77 ];
78 }
79
80 /**
81 * Method is used to calculate the trend based on the sums of the "amount"
82 * key from the two given periods.
83 *
84 * @param Collection $currentPeriod Statistics for the current period
85 * @param Collection $previousPeriod Statistics for the previous period
86 *
87 * @return string One of the TREND_* constants
88 */
89 private function calculateTrendFromPeriods(Collection $currentPeriod, Collection $previousPeriod): string
90 {
91 $statisticSumCurrentPeriod = $currentPeriod->sum('amount');
92 $statisticSumPreviousPeriod = $previousPeriod->sum('amount');
93
94 if ($statisticSumCurrentPeriod > $statisticSumPreviousPeriod) {
95 return self::TREND_UP;
96 }
97
98 if ($statisticSumCurrentPeriod < $statisticSumPreviousPeriod) {
99 return self::TREND_DOWN;
100 }
101
102 return self::TREND_STABLE;
103 }
104
105 /**
106 * Returns the used 'start' and 'end' filters for the given statistic. Uses
107 * the given filters first, and if they are missing, uses the filters from
108 * the used statistic instance.
109 *
110 * @throws \InvalidArgumentException When start or end filters are missing
111 * even when using the statistic's filters.
112 */
113 private function getCurrentPeriodFilters(array $filters, TimelineStatistics $statistic): array
114 {
115 if (empty($filters['start']) || empty($filters['end'])) {
116 $filters = $statistic->getFilters();
117 }
118
119 if (empty($filters) || empty($filters['start']) || empty($filters['end'])) {
120 throw new \InvalidArgumentException("Filters 'start' and 'end' are required to process statistic filters");
121 }
122
123 return $filters;
124 }
125 }
126