1 | <?php |
||||
2 | /** |
||||
3 | * @link https://dukt.net/analytics/ |
||||
4 | * @copyright Copyright (c) 2022, Dukt |
||||
5 | * @license https://github.com/dukt/analytics/blob/master/LICENSE.md |
||||
6 | */ |
||||
7 | |||||
8 | namespace dukt\analytics\controllers; |
||||
9 | |||||
10 | use Craft; |
||||
11 | use craft\web\Controller; |
||||
12 | use dukt\analytics\errors\InvalidChartTypeException; |
||||
13 | use dukt\analytics\Plugin as Analytics; |
||||
14 | use yii\web\Response; |
||||
15 | |||||
16 | class ReportsController extends Controller |
||||
17 | { |
||||
18 | // Public Methods |
||||
19 | // ========================================================================= |
||||
20 | |||||
21 | /** |
||||
22 | * E-commerce Report |
||||
23 | * |
||||
24 | * @return null |
||||
25 | * @throws \Google_Service_Exception |
||||
26 | * @throws \yii\base\InvalidConfigException |
||||
27 | */ |
||||
28 | public function actionEcommerceWidget() |
||||
29 | { |
||||
30 | if (Analytics::getInstance()->getAnalytics()->demoMode) { |
||||
31 | return $this->getEcommerceDemoResponse(); |
||||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||||
32 | } |
||||
33 | |||||
34 | $viewId = Craft::$app->getRequest()->getBodyParam('viewId'); |
||||
35 | $period = Craft::$app->getRequest()->getBodyParam('period'); |
||||
36 | |||||
37 | try { |
||||
38 | $response = Analytics::$plugin->getReports()->getEcommerceReport($viewId, $period); |
||||
39 | } catch(\Google_Service_Exception $e) { |
||||
40 | return $this->handleGoogleServiceException($e); |
||||
0 ignored issues
–
show
|
|||||
41 | } |
||||
42 | |||||
43 | return $this->asJson($response); |
||||
0 ignored issues
–
show
|
|||||
44 | } |
||||
45 | |||||
46 | /** |
||||
47 | * Get element report. |
||||
48 | * |
||||
49 | * @return Response |
||||
50 | * @throws \Google_Service_Exception |
||||
51 | * @throws \yii\base\InvalidConfigException |
||||
52 | * @throws \yii\web\BadRequestHttpException |
||||
53 | */ |
||||
54 | public function actionElement() |
||||
55 | { |
||||
56 | $elementId = Craft::$app->getRequest()->getRequiredParam('elementId'); |
||||
57 | $siteId = (int)Craft::$app->getRequest()->getRequiredParam('siteId'); |
||||
58 | $metric = Craft::$app->getRequest()->getRequiredParam('metric'); |
||||
59 | |||||
60 | try { |
||||
61 | $response = Analytics::$plugin->getReports()->getElementReport($elementId, $siteId, $metric); |
||||
62 | } catch(\Google_Service_Exception $e) { |
||||
63 | return $this->handleGoogleServiceException($e); |
||||
64 | } |
||||
65 | |||||
66 | return $this->asJson([ |
||||
67 | 'type' => 'area', |
||||
68 | 'chart' => $response |
||||
69 | ]); |
||||
70 | } |
||||
71 | |||||
72 | /** |
||||
73 | * Get realtime widget report. |
||||
74 | * |
||||
75 | * @return Response |
||||
76 | * @throws \Google_Exception |
||||
77 | * @throws \yii\base\InvalidConfigException |
||||
78 | */ |
||||
79 | public function actionRealtimeWidget() |
||||
80 | { |
||||
81 | if (Analytics::getInstance()->getAnalytics()->demoMode) { |
||||
82 | return $this->getRealtimeDemoResponse(); |
||||
83 | } |
||||
84 | |||||
85 | |||||
86 | // Active users |
||||
87 | |||||
88 | $activeUsers = 0; |
||||
89 | |||||
90 | $viewId = Craft::$app->getRequest()->getBodyParam('viewId'); |
||||
91 | |||||
92 | $request = [ |
||||
93 | 'viewId' => $viewId, |
||||
94 | 'metrics' => 'ga:activeVisitors', |
||||
95 | 'optParams' => [] |
||||
96 | ]; |
||||
97 | |||||
98 | try { |
||||
99 | $response = Analytics::$plugin->getReports()->getRealtimeReport($request); |
||||
100 | } catch(\Google_Service_Exception $e) { |
||||
101 | return $this->handleGoogleServiceException($e); |
||||
102 | } |
||||
103 | |||||
104 | if (!empty($response['totalsForAllResults']) && isset($response['totalsForAllResults']['ga:activeVisitors'])) { |
||||
105 | $activeUsers = $response['totalsForAllResults']['ga:activeVisitors']; |
||||
106 | } |
||||
107 | |||||
108 | |||||
109 | // Pageviews |
||||
110 | |||||
111 | $pageviewsRequest = [ |
||||
112 | 'viewId' => $viewId, |
||||
113 | 'metrics' => 'rt:pageviews', |
||||
114 | 'optParams' => ['dimensions' => 'rt:minutesAgo'] |
||||
115 | ]; |
||||
116 | |||||
117 | $pageviews = Analytics::$plugin->getReports()->getRealtimeReport($pageviewsRequest); |
||||
118 | |||||
119 | |||||
120 | // Active pages |
||||
121 | |||||
122 | $activePagesRequest = [ |
||||
123 | 'viewId' => $viewId, |
||||
124 | 'metrics' => 'rt:activeUsers', |
||||
125 | 'optParams' => ['dimensions' => 'rt:pagePath', 'max-results' => 5] |
||||
126 | ]; |
||||
127 | |||||
128 | $activePages = Analytics::$plugin->getReports()->getRealtimeReport($activePagesRequest); |
||||
129 | |||||
130 | return $this->asJson([ |
||||
131 | 'activeUsers' => $activeUsers, |
||||
132 | 'pageviews' => $pageviews, |
||||
133 | 'activePages' => $activePages, |
||||
134 | ]); |
||||
135 | } |
||||
136 | |||||
137 | /** |
||||
138 | * Get report widget report. |
||||
139 | * |
||||
140 | * @return Response |
||||
141 | * @throws InvalidChartTypeException |
||||
142 | * @throws \Google_Service_Exception |
||||
143 | * @throws \yii\base\InvalidConfigException |
||||
144 | */ |
||||
145 | public function actionReportWidget() |
||||
146 | { |
||||
147 | $viewId = Craft::$app->getRequest()->getBodyParam('viewId'); |
||||
148 | $chart = Craft::$app->getRequest()->getBodyParam('chart'); |
||||
149 | $period = Craft::$app->getRequest()->getBodyParam('period'); |
||||
150 | $options = Craft::$app->getRequest()->getBodyParam('options'); |
||||
151 | |||||
152 | $request = [ |
||||
153 | 'viewId' => $viewId, |
||||
154 | 'chart' => $chart, |
||||
155 | 'period' => $period, |
||||
156 | 'options' => $options, |
||||
157 | ]; |
||||
158 | |||||
159 | $cacheId = ['getReport', $request]; |
||||
160 | |||||
161 | try { |
||||
162 | $response = Analytics::$plugin->cache->get($cacheId); |
||||
163 | |||||
164 | if (!$response) { |
||||
165 | switch ($chart) { |
||||
166 | case 'area': |
||||
167 | $response = Analytics::$plugin->getReports()->getAreaReport($request); |
||||
168 | break; |
||||
169 | case 'counter': |
||||
170 | $response = Analytics::$plugin->getReports()->getCounterReport($request); |
||||
171 | break; |
||||
172 | case 'pie': |
||||
173 | $response = Analytics::$plugin->getReports()->getPieReport($request); |
||||
174 | break; |
||||
175 | case 'table': |
||||
176 | $response = Analytics::$plugin->getReports()->getTableReport($request); |
||||
177 | break; |
||||
178 | case 'geo': |
||||
179 | $response = Analytics::$plugin->getReports()->getGeoReport($request); |
||||
180 | break; |
||||
181 | default: |
||||
182 | throw new InvalidChartTypeException('Chart type `'.$chart.'` not supported.'); |
||||
183 | } |
||||
184 | |||||
185 | if ($response) { |
||||
186 | Analytics::$plugin->cache->set($cacheId, $response); |
||||
187 | } |
||||
188 | } |
||||
189 | |||||
190 | |||||
191 | return $this->asJson($response); |
||||
192 | } catch(\Google_Service_Exception $e) { |
||||
193 | return $this->handleGoogleServiceException($e); |
||||
194 | } |
||||
195 | } |
||||
196 | |||||
197 | // Private Methods |
||||
198 | // ========================================================================= |
||||
199 | |||||
200 | /** |
||||
201 | * Handle Google service exception. |
||||
202 | * |
||||
203 | * @param \Google_Service_Exception $e |
||||
204 | * @return Response |
||||
205 | * @throws \Google_Service_Exception |
||||
206 | */ |
||||
207 | private function handleGoogleServiceException(\Google_Service_Exception $e): Response |
||||
208 | { |
||||
209 | $errors = $e->getErrors(); |
||||
210 | |||||
211 | if(empty($errors)) { |
||||
212 | throw $e; |
||||
213 | } |
||||
214 | |||||
215 | Craft::error("Couldn’t generate Report widget’s report: \r\n".print_r($errors, true)."\r\n".$e->getTraceAsString(), __METHOD__); |
||||
0 ignored issues
–
show
Are you sure
print_r($errors, true) of type string|true can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
216 | |||||
217 | return $this->asErrorJson($errors[0]['message']); |
||||
218 | } |
||||
219 | |||||
220 | /** |
||||
221 | * Get realtime demo response. |
||||
222 | * |
||||
223 | * @return Response |
||||
224 | * @throws \yii\base\InvalidConfigException |
||||
225 | */ |
||||
226 | private function getRealtimeDemoResponse(): Response |
||||
227 | { |
||||
228 | if (Analytics::$plugin->getAnalytics()->demoMode === 'test') { |
||||
229 | return $this->getRealtimeDemoTestResponse(); |
||||
230 | } |
||||
231 | |||||
232 | $pageviews = [ |
||||
233 | 'rows' => [] |
||||
234 | ]; |
||||
235 | |||||
236 | for ($i = 0; $i <= 30; $i++) { |
||||
237 | $pageviews['rows'][] = [$i, random_int(0, 20)]; |
||||
238 | } |
||||
239 | |||||
240 | $activePages = [ |
||||
241 | 'rows' => [ |
||||
242 | ['/a-new-toga/', random_int(1, 20)], |
||||
243 | ['/parka-with-stripes-on-back/', random_int(1, 20)], |
||||
244 | ['/romper-for-a-red-eye/', random_int(1, 20)], |
||||
245 | ['/the-fleece-awakens/', random_int(1, 20)], |
||||
246 | ['/the-last-knee-high/', random_int(1, 20)], |
||||
247 | ] |
||||
248 | ]; |
||||
249 | |||||
250 | $activeUsers = 0; |
||||
251 | |||||
252 | foreach ($activePages['rows'] as $row) { |
||||
253 | $activeUsers += $row[1]; |
||||
254 | } |
||||
255 | |||||
256 | return $this->asJson([ |
||||
257 | 'activeUsers' => $activeUsers, |
||||
258 | 'pageviews' => $pageviews, |
||||
259 | 'activePages' => $activePages, |
||||
260 | ]); |
||||
261 | } |
||||
262 | |||||
263 | /** |
||||
264 | * Get realtime demo test response. |
||||
265 | * |
||||
266 | * @return Response |
||||
267 | * @throws \Exception |
||||
268 | */ |
||||
269 | private function getRealtimeDemoTestResponse(): Response |
||||
270 | { |
||||
271 | $pageviews = [ |
||||
272 | 'rows' => [] |
||||
273 | ]; |
||||
274 | |||||
275 | for ($i = 0; $i <= 30; $i++) { |
||||
276 | $pageviews['rows'][] = [$i, random_int(0, 20)]; |
||||
277 | } |
||||
278 | |||||
279 | $activePages = [ |
||||
280 | 'rows' => [ |
||||
281 | ['/some-url/', random_int(1, 20)], |
||||
282 | ['/some-super-long-url/with-kebab-case/', random_int(1, 20)], |
||||
283 | ['/somesuperlongurlwithoutkebabcasebutstillsuperlong/', random_int(10000000, 20000000)], |
||||
284 | ['/someothersuperlongurl/withoutkebabcasebutstillsuperlong/', random_int(1, 20)], |
||||
285 | ['/one-last-url/', random_int(1, 20)], |
||||
286 | ] |
||||
287 | ]; |
||||
288 | |||||
289 | $activeUsers = 0; |
||||
290 | |||||
291 | foreach ($activePages['rows'] as $row) { |
||||
292 | $activeUsers += $row[1]; |
||||
293 | } |
||||
294 | |||||
295 | return $this->asJson([ |
||||
296 | 'activeUsers' => $activeUsers, |
||||
297 | 'pageviews' => $pageviews, |
||||
298 | 'activePages' => $activePages, |
||||
299 | ]); |
||||
300 | } |
||||
301 | |||||
302 | /** |
||||
303 | * @return Response |
||||
304 | * @throws \Exception |
||||
305 | */ |
||||
306 | private function getEcommerceDemoResponse(): Response |
||||
307 | { |
||||
308 | $date = new \DateTime(); |
||||
309 | $date = $date->modify('-12 months'); |
||||
310 | $rows = []; |
||||
311 | |||||
312 | for ($i = 1; $i <= 12; $i++) { |
||||
313 | $rows[] = [ |
||||
314 | $date->format('Ym'), |
||||
315 | random_int(50000, 150000) |
||||
316 | ]; |
||||
317 | |||||
318 | $date->modify('+1 month'); |
||||
319 | } |
||||
320 | |||||
321 | $reportData = [ |
||||
322 | 'chart' => [ |
||||
323 | 'cols' => [ |
||||
324 | [ |
||||
325 | 'id' => 'ga:yearMonth', |
||||
326 | 'label' => 'Month of Year', |
||||
327 | 'type' => 'date', |
||||
328 | ], |
||||
329 | [ |
||||
330 | 'id' => 'ga:transactionRevenue', |
||||
331 | 'label' => 'Revenue', |
||||
332 | 'type' => 'currency', |
||||
333 | ], |
||||
334 | ], |
||||
335 | 'rows' => $rows, |
||||
336 | 'totals' => [ |
||||
337 | [ |
||||
338 | '11385.0', |
||||
339 | '97.3076923076923', |
||||
340 | ] |
||||
341 | ], |
||||
342 | ], |
||||
343 | 'period' => 'year', |
||||
344 | 'periodLabel' => 'This year', |
||||
345 | 'view' => 'Craft Shop', |
||||
346 | ]; |
||||
347 | |||||
348 | $totalRevenue = 0; |
||||
349 | |||||
350 | foreach($rows as $row) { |
||||
351 | $totalRevenue += $row[1]; |
||||
352 | } |
||||
353 | |||||
354 | $totalTransactions = random_int(3400, 3800); |
||||
355 | $totalRevenuePerTransaction = $totalRevenue / $totalTransactions; |
||||
356 | $totalTransactionsPerSession = 8.291991495393338; |
||||
357 | |||||
358 | return $this->asJson([ |
||||
359 | 'period' => '365daysAgo - today', |
||||
360 | 'reportData' => $reportData, |
||||
361 | 'totalRevenue' => $totalRevenue, |
||||
362 | 'totalRevenuePerTransaction' => $totalRevenuePerTransaction, |
||||
363 | 'totalTransactions' => $totalTransactions, |
||||
364 | 'totalTransactionsPerSession' => $totalTransactionsPerSession, |
||||
365 | ]); |
||||
366 | } |
||||
367 | } |
||||
368 |