PluginProbe
Metricool – Social media and site statistics / 2.1.1
Metricool – Social media and site statistics v2.1.1
2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.27 trunk
← All changes | app/Http/Metricool/Entities/TimelineStatistics.php +152 -0 2.0.1 → 2.1.1 View file →
@@ -1,0 +1,152 @@
1 +<?php
2 +
3 +declare(strict_types=1);
4 +
5 +namespace Metricool\Http\Metricool\Entities;
6 +
7 +use Metricool\Vendor\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 +}