PluginProbe
Metricool – Social media and site statistics / 2.0.2
Metricool – Social media and site statistics v2.0.2
2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.27 trunk
metricool / app / Http / Metricool / Entities / TimelineStatistics.php

TimelineStatistics.php in Metricool – Social media and site statistics 2.0.2, at app/Http/Metricool/Entities/TimelineStatistics.php

153 lines 4.2 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\Http\Metricool\Entities;
6
7 use Carbon\Carbon;
8 use Metricool\Http\Metricool\Exceptions\ApiException;
9 use Metricool\Support\Helpers\Collection;
10 use Metricool\Http\Metricool\DTOs\TimelineDTO;
11 use Metricool\Http\Metricool\MetricoolClient;
12 use Metricool\Http\Metricool\Traits\IsFilterable;
13 use Metricool\Traits\IsHydratable;
14 use Metricool\Http\Metricool\Filters\PeriodFilter;
15
16 /**
17 * API responses for the timeline statistics contain of array entries where each
18 * entry reflects a timestamp and its corresponding value for the metric.
19 * Example: [
20 * "1752170400000",
21 * "981.0"
22 * ]
23 */
24 class TimelineStatistics
25 {
26 use IsFilterable;
27 use IsHydratable;
28
29 protected string $metric;
30 protected MetricoolClient $client;
31
32 public string $endpoint = 'stats/timeline/';
33
34 /**
35 * The timeline statistics API is compatible with these metrics.
36 */
37 private array $compatibleMetrics = [
38 'PageViews',
39 'SessionsCount',
40 'Visitors',
41 'DailyPosts',
42 'DailyComments',
43 ];
44
45 /**
46 * Pass a compatible metric to the constructor: {@see compatibleMetrics}
47 * @throws \InvalidArgumentException
48 */
49 public function __construct(MetricoolClient $client, string $metric, bool $filterRequired = true)
50 {
51 $this->metric = $metric;
52
53 if (!in_array($this->metric, $this->compatibleMetrics)) {
54 throw new \InvalidArgumentException(esc_html("Incompatible metric given: $this->metric"));
55 }
56
57 $this->client = $client;
58 $this->endpoint .= $this->metric;
59 $this->requiresFilter = $filterRequired;
60
61 /**
62 * The distribution statistics API need a filter by default to prevent
63 * Internal Server errors on the remote server. We set the default
64 * filters to the last 30 days.
65 */
66 $this->filters = [
67 'start' => Carbon::now()->subDays(30)->format('Ymd'),
68 'end' => Carbon::now()->format('Ymd'),
69 ];
70 }
71
72 /**
73 * @inheritDoc
74 */
75 protected function getAcceptedFilters(): array
76 {
77 return [
78 'start' => '/^\d+$/',
79 'end' => '/^\d+$/',
80 'period' => '/^[a-z0-9]+$/i',
81 ];
82 }
83
84 /**
85 * Applies the period filter
86 * @see \Metricool\Http\Metricool\Traits\IsFilterable::doFilter
87 */
88 protected function applyPeriodFilter(string $period): void
89 {
90 $filter = PeriodFilter::parse($period, true);
91 $this->applyFilters([
92 'start' => $filter->getStartDate()->format('Ymd'),
93 'end' => $filter->getEndDate()->format('Ymd'),
94 ]);
95 }
96
97 /**
98 * Hydrates a result:
99 * [
100 * "1752170400000",
101 * "981.0"
102 * ]
103 * Into a TimelineStatisticDTO object.
104 */
105 protected function hydrateItem($key, $item): TimelineDTO
106 {
107 return (new TimelineDTO((int) $item[0], (float) $item[1]));
108 }
109
110 /**
111 * Fetch and return the timeline statistics data plainly from the API.
112 * @return Collection|TimelineDTO[]
113 * @throws ApiException
114 */
115 public function get(): Collection
116 {
117 if ($this->requiresFilter && $this->filtered === false) {
118 $this->filter($this->filters);
119 }
120
121 $results = $this->client->get($this->endpoint);
122
123 if ($this->isEmptyResponse($results)) {
124 return new Collection([]);
125 }
126
127 $results = $this->hydrateResults($results);
128
129 return $results;
130 }
131
132 /**
133 * Return the metric that the current instance is used for. Useful for
134 * dynamic retrieval of the intent of the instance. For an example see:
135 * {@see \Metricool\Services\AnalyticsService::getTrend}
136 */
137 public function getMetric(): string
138 {
139 return $this->metric;
140 }
141
142 /**
143 * When this endpoint holds no data, Metricool returns a result with
144 * non-standard output. Just return an empty response when only 1 row is
145 * found in the results and the value is 0
146 * @param mixed $response
147 */
148 protected function isEmptyResponse($response): bool
149 {
150 return empty($response) || (is_array($response) && count($response) === 1 && empty($response[0][1]));
151 }
152 }
153