PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.1.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.1.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / DataArray.php
matomo / app / core Last commit date
API 6 years ago Access 6 years ago Application 6 years ago Archive 6 years ago ArchiveProcessor 6 years ago Archiver 6 years ago AssetManager 6 years ago Auth 6 years ago Category 6 years ago CliMulti 6 years ago Columns 6 years ago Composer 6 years ago Concurrency 6 years ago Config 6 years ago Container 6 years ago CronArchive 6 years ago DataAccess 6 years ago DataFiles 6 years ago DataTable 6 years ago Db 6 years ago DeviceDetector 6 years ago Email 6 years ago Exception 6 years ago Http 6 years ago Intl 6 years ago Mail 6 years ago Measurable 6 years ago Menu 6 years ago Metrics 6 years ago Notification 6 years ago Period 6 years ago Plugin 6 years ago ProfessionalServices 6 years ago Report 6 years ago ReportRenderer 6 years ago Scheduler 6 years ago Segment 6 years ago Session 6 years ago Settings 6 years ago Tracker 6 years ago Translation 6 years ago UpdateCheck 6 years ago Updater 6 years ago Updates 6 years ago Validators 6 years ago View 6 years ago ViewDataTable 6 years ago Visualization 6 years ago Widget 6 years ago .htaccess 6 years ago Access.php 6 years ago Archive.php 6 years ago ArchiveProcessor.php 6 years ago AssetManager.php 6 years ago Auth.php 6 years ago BaseFactory.php 6 years ago Cache.php 6 years ago CacheId.php 6 years ago CliMulti.php 6 years ago Common.php 6 years ago Config.php 6 years ago Console.php 6 years ago Context.php 6 years ago Cookie.php 6 years ago CronArchive.php 6 years ago DataArray.php 6 years ago DataTable.php 6 years ago Date.php 6 years ago Db.php 6 years ago DbHelper.php 6 years ago Development.php 6 years ago DeviceDetectorFactory.php 6 years ago ErrorHandler.php 6 years ago EventDispatcher.php 6 years ago ExceptionHandler.php 6 years ago FileIntegrity.php 6 years ago Filechecks.php 6 years ago Filesystem.php 6 years ago FrontController.php 6 years ago Http.php 6 years ago IP.php 6 years ago Log.php 6 years ago LogDeleter.php 6 years ago Mail.php 6 years ago Metrics.php 6 years ago MetricsFormatter.php 6 years ago Nonce.php 6 years ago Notification.php 6 years ago NumberFormatter.php 6 years ago Option.php 6 years ago Period.php 6 years ago Piwik.php 6 years ago Plugin.php 6 years ago Profiler.php 6 years ago ProxyHeaders.php 6 years ago ProxyHttp.php 6 years ago QuickForm2.php 6 years ago RankingQuery.php 6 years ago Registry.php 6 years ago ReportRenderer.php 6 years ago ScheduledTask.php 6 years ago Segment.php 6 years ago Sequence.php 6 years ago Session.php 6 years ago SettingsPiwik.php 6 years ago SettingsServer.php 6 years ago Singleton.php 6 years ago Site.php 6 years ago TCPDF.php 6 years ago TaskScheduler.php 6 years ago Theme.php 6 years ago Timer.php 6 years ago Tracker.php 6 years ago Translate.php 6 years ago Twig.php 6 years ago Unzip.php 6 years ago UpdateCheck.php 6 years ago Updater.php 6 years ago Updates.php 6 years ago Url.php 6 years ago UrlHelper.php 6 years ago Version.php 6 years ago View.php 6 years ago bootstrap.php 6 years ago dispatch.php 6 years ago testMinimumPhpVersion.php 6 years ago
DataArray.php
440 lines
1 <?php
2 /**
3 * Piwik - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik;
10
11 use Exception;
12 use Piwik\Tracker\GoalManager;
13
14 /**
15 * The DataArray is a data structure used to aggregate datasets,
16 * ie. sum arrays made of rows made of columns,
17 * data from the logs is stored in a DataArray before being converted in a DataTable
18 *
19 */
20
21 class DataArray
22 {
23 protected $data = array();
24 protected $dataTwoLevels = array();
25
26 public function __construct($data = array(), $dataArrayByLabel = array())
27 {
28 $this->data = $data;
29 $this->dataTwoLevels = $dataArrayByLabel;
30 }
31
32 /**
33 * This returns the actual raw data array
34 *
35 * @return array
36 */
37 public function &getDataArray()
38 {
39 return $this->data;
40 }
41
42 public function getDataArrayWithTwoLevels()
43 {
44 return $this->dataTwoLevels;
45 }
46
47 public function sumMetricsVisits($label, $row)
48 {
49 if (!isset($this->data[$label])) {
50 $this->data[$label] = static::makeEmptyRow();
51 }
52 $this->doSumVisitsMetrics($row, $this->data[$label]);
53 }
54
55 /**
56 * Returns an empty row containing default metrics
57 *
58 * @return array
59 */
60 public static function makeEmptyRow()
61 {
62 return array(Metrics::INDEX_NB_UNIQ_VISITORS => 0,
63 Metrics::INDEX_NB_VISITS => 0,
64 Metrics::INDEX_NB_ACTIONS => 0,
65 Metrics::INDEX_NB_USERS => 0,
66 Metrics::INDEX_MAX_ACTIONS => 0,
67 Metrics::INDEX_SUM_VISIT_LENGTH => 0,
68 Metrics::INDEX_BOUNCE_COUNT => 0,
69 Metrics::INDEX_NB_VISITS_CONVERTED => 0,
70 );
71 }
72
73 /**
74 * Adds the given row $newRowToAdd to the existing $oldRowToUpdate passed by reference
75 * The rows are php arrays Name => value
76 *
77 * @param array $newRowToAdd
78 * @param array $oldRowToUpdate
79 * @param bool $onlyMetricsAvailableInActionsTable
80 *
81 * @return void
82 */
83 protected function doSumVisitsMetrics($newRowToAdd, &$oldRowToUpdate)
84 {
85 // Pre 1.2 format: string indexed rows are returned from the DB
86 // Left here for Backward compatibility with plugins doing custom SQL queries using these metrics as string
87 if (!isset($newRowToAdd[Metrics::INDEX_NB_VISITS])) {
88 $oldRowToUpdate[Metrics::INDEX_NB_VISITS] += $newRowToAdd['nb_visits'];
89 $oldRowToUpdate[Metrics::INDEX_NB_ACTIONS] += $newRowToAdd['nb_actions'];
90 $oldRowToUpdate[Metrics::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd['nb_uniq_visitors'];
91 $oldRowToUpdate[Metrics::INDEX_NB_USERS] += $newRowToAdd['nb_users'];
92 $oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS] = (float)max($newRowToAdd['max_actions'], $oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS]);
93 $oldRowToUpdate[Metrics::INDEX_SUM_VISIT_LENGTH] += $newRowToAdd['sum_visit_length'];
94 $oldRowToUpdate[Metrics::INDEX_BOUNCE_COUNT] += $newRowToAdd['bounce_count'];
95 $oldRowToUpdate[Metrics::INDEX_NB_VISITS_CONVERTED] += $newRowToAdd['nb_visits_converted'];
96 return;
97 }
98
99 // Edge case fail safe
100 if (!isset($oldRowToUpdate[Metrics::INDEX_NB_VISITS])) {
101 return;
102 }
103
104 $oldRowToUpdate[Metrics::INDEX_NB_VISITS] += $newRowToAdd[Metrics::INDEX_NB_VISITS];
105 $oldRowToUpdate[Metrics::INDEX_NB_ACTIONS] += $newRowToAdd[Metrics::INDEX_NB_ACTIONS];
106 $oldRowToUpdate[Metrics::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd[Metrics::INDEX_NB_UNIQ_VISITORS];
107
108 // In case the existing Row had no action metrics (eg. Custom Variable XYZ with "visit" scope)
109 // but the new Row has action metrics (eg. same Custom Variable XYZ this time with a "page" scope)
110 if (!isset($oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS])) {
111 $toZero = array(
112 Metrics::INDEX_NB_USERS,
113 Metrics::INDEX_MAX_ACTIONS,
114 Metrics::INDEX_SUM_VISIT_LENGTH,
115 Metrics::INDEX_BOUNCE_COUNT,
116 Metrics::INDEX_NB_VISITS_CONVERTED
117 );
118 foreach ($toZero as $metric) {
119 $oldRowToUpdate[$metric] = 0;
120 }
121 }
122
123 $oldRowToUpdate[Metrics::INDEX_NB_USERS] += $newRowToAdd[Metrics::INDEX_NB_USERS];
124 $oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS] = (float)max($newRowToAdd[Metrics::INDEX_MAX_ACTIONS], $oldRowToUpdate[Metrics::INDEX_MAX_ACTIONS]);
125 $oldRowToUpdate[Metrics::INDEX_SUM_VISIT_LENGTH] += $newRowToAdd[Metrics::INDEX_SUM_VISIT_LENGTH];
126 $oldRowToUpdate[Metrics::INDEX_BOUNCE_COUNT] += $newRowToAdd[Metrics::INDEX_BOUNCE_COUNT];
127 $oldRowToUpdate[Metrics::INDEX_NB_VISITS_CONVERTED] += $newRowToAdd[Metrics::INDEX_NB_VISITS_CONVERTED];
128 }
129
130 /**
131 * Adds the given row $newRowToAdd to the existing $oldRowToUpdate passed by reference
132 * The rows are php arrays Name => value
133 *
134 * @param array $newRowToAdd
135 * @param array $oldRowToUpdate
136 * @param bool $onlyMetricsAvailableInActionsTable
137 *
138 * @return void
139 */
140 protected function doSumActionsMetrics($newRowToAdd, &$oldRowToUpdate)
141 {
142 // Pre 1.2 format: string indexed rows are returned from the DB
143 // Left here for Backward compatibility with plugins doing custom SQL queries using these metrics as string
144 if (!isset($newRowToAdd[Metrics::INDEX_NB_VISITS])) {
145 $oldRowToUpdate[Metrics::INDEX_NB_VISITS] += $newRowToAdd['nb_visits'];
146 $oldRowToUpdate[Metrics::INDEX_NB_ACTIONS] += $newRowToAdd['nb_actions'];
147 $oldRowToUpdate[Metrics::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd['nb_uniq_visitors'];
148 return;
149 }
150
151 // Edge case fail safe
152 if (!isset($oldRowToUpdate[Metrics::INDEX_NB_VISITS])) {
153 return;
154 }
155
156 $oldRowToUpdate[Metrics::INDEX_NB_VISITS] += $newRowToAdd[Metrics::INDEX_NB_VISITS];
157 if (array_key_exists(Metrics::INDEX_NB_ACTIONS, $newRowToAdd)) {
158 $oldRowToUpdate[Metrics::INDEX_NB_ACTIONS] += $newRowToAdd[Metrics::INDEX_NB_ACTIONS];
159 }
160 if (array_key_exists(Metrics::INDEX_PAGE_NB_HITS, $newRowToAdd)) {
161 if (!array_key_exists(Metrics::INDEX_PAGE_NB_HITS, $oldRowToUpdate)) {
162 $oldRowToUpdate[Metrics::INDEX_PAGE_NB_HITS] = 0;
163 }
164 $oldRowToUpdate[Metrics::INDEX_PAGE_NB_HITS] += $newRowToAdd[Metrics::INDEX_PAGE_NB_HITS];
165 }
166 $oldRowToUpdate[Metrics::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd[Metrics::INDEX_NB_UNIQ_VISITORS];
167 }
168
169 public function sumMetricsGoals($label, $row)
170 {
171 $idGoal = $row['idgoal'];
172 if (!isset($this->data[$label][Metrics::INDEX_GOALS][$idGoal])) {
173 $this->data[$label][Metrics::INDEX_GOALS][$idGoal] = static::makeEmptyGoalRow($idGoal);
174 }
175 $this->doSumGoalsMetrics($row, $this->data[$label][Metrics::INDEX_GOALS][$idGoal]);
176 }
177
178 /**
179 * @param $idGoal
180 * @return array
181 */
182 protected static function makeEmptyGoalRow($idGoal)
183 {
184 if ($idGoal > GoalManager::IDGOAL_ORDER) {
185 return array(Metrics::INDEX_GOAL_NB_CONVERSIONS => 0,
186 Metrics::INDEX_GOAL_NB_VISITS_CONVERTED => 0,
187 Metrics::INDEX_GOAL_REVENUE => 0,
188 );
189 }
190 if ($idGoal == GoalManager::IDGOAL_ORDER) {
191 return array(Metrics::INDEX_GOAL_NB_CONVERSIONS => 0,
192 Metrics::INDEX_GOAL_NB_VISITS_CONVERTED => 0,
193 Metrics::INDEX_GOAL_REVENUE => 0,
194 Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL => 0,
195 Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_TAX => 0,
196 Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SHIPPING => 0,
197 Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT => 0,
198 Metrics::INDEX_GOAL_ECOMMERCE_ITEMS => 0,
199 );
200 }
201 // idGoal == GoalManager::IDGOAL_CART
202 return array(Metrics::INDEX_GOAL_NB_CONVERSIONS => 0,
203 Metrics::INDEX_GOAL_NB_VISITS_CONVERTED => 0,
204 Metrics::INDEX_GOAL_REVENUE => 0,
205 Metrics::INDEX_GOAL_ECOMMERCE_ITEMS => 0,
206 );
207 }
208
209 /**
210 *
211 * @param $newRowToAdd
212 * @param $oldRowToUpdate
213 */
214 protected function doSumGoalsMetrics($newRowToAdd, &$oldRowToUpdate)
215 {
216 $oldRowToUpdate[Metrics::INDEX_GOAL_NB_CONVERSIONS] += $newRowToAdd[Metrics::INDEX_GOAL_NB_CONVERSIONS];
217 $oldRowToUpdate[Metrics::INDEX_GOAL_NB_VISITS_CONVERTED] += $newRowToAdd[Metrics::INDEX_GOAL_NB_VISITS_CONVERTED];
218 $oldRowToUpdate[Metrics::INDEX_GOAL_REVENUE] += $newRowToAdd[Metrics::INDEX_GOAL_REVENUE];
219
220 // Cart & Order
221 if (isset($oldRowToUpdate[Metrics::INDEX_GOAL_ECOMMERCE_ITEMS])) {
222 $oldRowToUpdate[Metrics::INDEX_GOAL_ECOMMERCE_ITEMS] += $newRowToAdd[Metrics::INDEX_GOAL_ECOMMERCE_ITEMS];
223
224 // Order only
225 if (isset($oldRowToUpdate[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL])) {
226 $oldRowToUpdate[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL] += $newRowToAdd[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SUBTOTAL];
227 $oldRowToUpdate[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_TAX] += $newRowToAdd[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_TAX];
228 $oldRowToUpdate[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SHIPPING] += $newRowToAdd[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_SHIPPING];
229 $oldRowToUpdate[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT] += $newRowToAdd[Metrics::INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT];
230 }
231 }
232 }
233
234 public function sumMetricsActions($label, $row)
235 {
236 if (!isset($this->data[$label])) {
237 $this->data[$label] = static::makeEmptyActionRow();
238 }
239
240 $this->doSumActionsMetrics($row, $this->data[$label]);
241 }
242
243 protected static function makeEmptyActionRow()
244 {
245 return array(
246 Metrics::INDEX_NB_UNIQ_VISITORS => 0,
247 Metrics::INDEX_NB_VISITS => 0,
248 Metrics::INDEX_NB_ACTIONS => 0,
249 );
250 }
251
252 public function sumMetricsEvents($label, $row)
253 {
254 if (!isset($this->data[$label])) {
255 $this->data[$label] = static::makeEmptyEventRow();
256 }
257 $this->doSumEventsMetrics($row, $this->data[$label], $onlyMetricsAvailableInActionsTable = true);
258 }
259
260 protected static function makeEmptyEventRow()
261 {
262 return array(
263 Metrics::INDEX_NB_UNIQ_VISITORS => 0,
264 Metrics::INDEX_NB_VISITS => 0,
265 Metrics::INDEX_EVENT_NB_HITS => 0,
266 Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE => 0,
267 Metrics::INDEX_EVENT_SUM_EVENT_VALUE => 0,
268 Metrics::INDEX_EVENT_MIN_EVENT_VALUE => false,
269 Metrics::INDEX_EVENT_MAX_EVENT_VALUE => 0,
270 );
271 }
272
273 const EVENT_VALUE_PRECISION = 2;
274
275 /**
276 * @param array $newRowToAdd
277 * @param array $oldRowToUpdate
278 * @return void
279 */
280 protected function doSumEventsMetrics($newRowToAdd, &$oldRowToUpdate)
281 {
282 $oldRowToUpdate[Metrics::INDEX_NB_VISITS] += $newRowToAdd[Metrics::INDEX_NB_VISITS];
283 $oldRowToUpdate[Metrics::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd[Metrics::INDEX_NB_UNIQ_VISITORS];
284 $oldRowToUpdate[Metrics::INDEX_EVENT_NB_HITS] += $newRowToAdd[Metrics::INDEX_EVENT_NB_HITS];
285 $oldRowToUpdate[Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE] += $newRowToAdd[Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE];
286
287 $newRowToAdd[Metrics::INDEX_EVENT_SUM_EVENT_VALUE] = round($newRowToAdd[Metrics::INDEX_EVENT_SUM_EVENT_VALUE], static::EVENT_VALUE_PRECISION);
288 $oldRowToUpdate[Metrics::INDEX_EVENT_SUM_EVENT_VALUE] += $newRowToAdd[Metrics::INDEX_EVENT_SUM_EVENT_VALUE];
289 $oldRowToUpdate[Metrics::INDEX_EVENT_MAX_EVENT_VALUE] = round(max($newRowToAdd[Metrics::INDEX_EVENT_MAX_EVENT_VALUE], $oldRowToUpdate[Metrics::INDEX_EVENT_MAX_EVENT_VALUE]), static::EVENT_VALUE_PRECISION);
290
291 // Update minimum only if it is set
292 if ($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] !== false) {
293 if ($oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] === false) {
294 $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] = round($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE], static::EVENT_VALUE_PRECISION);
295 } else {
296 $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE] = round(min($newRowToAdd[Metrics::INDEX_EVENT_MIN_EVENT_VALUE], $oldRowToUpdate[Metrics::INDEX_EVENT_MIN_EVENT_VALUE]), static::EVENT_VALUE_PRECISION);
297 }
298 }
299 }
300
301 /**
302 * Generic function that will sum all columns of the given row, at the specified label's row.
303 *
304 * @param $label
305 * @param $row
306 * @throws Exception if the the data row contains non numeric values
307 */
308 public function sumMetrics($label, $row)
309 {
310 foreach ($row as $columnName => $columnValue) {
311 if (empty($columnValue)) {
312 continue;
313 }
314 if (empty($this->data[$label][$columnName])) {
315 $this->data[$label][$columnName] = 0;
316 }
317 if (!is_numeric($columnValue)) {
318 throw new Exception("DataArray->sumMetricsPivot expects rows of numeric values, non numeric found: " . var_export($columnValue, true) . " for column $columnName");
319 }
320 $this->data[$label][$columnName] += $columnValue;
321 }
322 }
323
324 public function sumMetricsVisitsPivot($parentLabel, $label, $row)
325 {
326 if (!isset($this->dataTwoLevels[$parentLabel][$label])) {
327 $this->dataTwoLevels[$parentLabel][$label] = static::makeEmptyRow();
328 }
329 $this->doSumVisitsMetrics($row, $this->dataTwoLevels[$parentLabel][$label]);
330 }
331
332 public function sumMetricsGoalsPivot($parentLabel, $label, $row)
333 {
334 $idGoal = $row['idgoal'];
335 if (!isset($this->dataTwoLevels[$parentLabel][$label][Metrics::INDEX_GOALS][$idGoal])) {
336 $this->dataTwoLevels[$parentLabel][$label][Metrics::INDEX_GOALS][$idGoal] = static::makeEmptyGoalRow($idGoal);
337 }
338 $this->doSumGoalsMetrics($row, $this->dataTwoLevels[$parentLabel][$label][Metrics::INDEX_GOALS][$idGoal]);
339 }
340
341 public function sumMetricsActionsPivot($parentLabel, $label, $row)
342 {
343 if (!isset($this->dataTwoLevels[$parentLabel][$label])) {
344 $this->dataTwoLevels[$parentLabel][$label] = $this->makeEmptyActionRow();
345 }
346 $this->doSumActionsMetrics($row, $this->dataTwoLevels[$parentLabel][$label]);
347 }
348
349 public function sumMetricsEventsPivot($parentLabel, $label, $row)
350 {
351 if (!isset($this->dataTwoLevels[$parentLabel][$label])) {
352 $this->dataTwoLevels[$parentLabel][$label] = $this->makeEmptyEventRow();
353 }
354 $this->doSumEventsMetrics($row, $this->dataTwoLevels[$parentLabel][$label]);
355 }
356
357 public function setRowColumnPivot($parentLabel, $label, $column, $value)
358 {
359 $this->dataTwoLevels[$parentLabel][$label][$column] = $value;
360 }
361
362 public function enrichMetricsWithConversions()
363 {
364 $this->enrichWithConversions($this->data);
365
366 foreach ($this->dataTwoLevels as &$metricsBySubLabel) {
367 $this->enrichWithConversions($metricsBySubLabel);
368 }
369 }
370
371 /**
372 * Given an array of stats, it will process the sum of goal conversions
373 * and sum of revenue and add it in the stats array in two new fields.
374 *
375 * @param array $data Passed by reference, two new columns
376 * will be added: total conversions, and total revenue, for all goals for this label/row
377 */
378 protected function enrichWithConversions(&$data)
379 {
380 foreach ($data as &$values) {
381 if (!isset($values[Metrics::INDEX_GOALS])) {
382 continue;
383 }
384
385 $revenue = $conversions = 0;
386 foreach ($values[Metrics::INDEX_GOALS] as $idgoal => $goalValues) {
387 // Do not sum Cart revenue since it is a lost revenue
388 if ($idgoal >= GoalManager::IDGOAL_ORDER) {
389 $revenue += $goalValues[Metrics::INDEX_GOAL_REVENUE];
390 $conversions += $goalValues[Metrics::INDEX_GOAL_NB_CONVERSIONS];
391 }
392 }
393 $values[Metrics::INDEX_NB_CONVERSIONS] = $conversions;
394
395 // 25.00 recorded as 25
396 if (round($revenue) == $revenue) {
397 $revenue = round($revenue);
398 }
399 $values[Metrics::INDEX_REVENUE] = $revenue;
400
401 // if there are no "visit" column, we force one to prevent future complications
402 // eg. This helps the setDefaultColumnsToDisplay() call
403 if (!isset($values[Metrics::INDEX_NB_VISITS])) {
404 $values[Metrics::INDEX_NB_VISITS] = 0;
405 }
406 }
407 }
408
409 /**
410 * Returns true if the row looks like an Action metrics row
411 *
412 * @param $row
413 * @return bool
414 */
415 public static function isRowActions($row)
416 {
417 return (count($row) == count(static::makeEmptyActionRow())) && isset($row[Metrics::INDEX_NB_ACTIONS]);
418 }
419
420 /**
421 * Converts array to a datatable
422 *
423 * @return \Piwik\DataTable
424 */
425 public function asDataTable()
426 {
427 $dataArray = $this->getDataArray();
428 $dataArrayTwoLevels = $this->getDataArrayWithTwoLevels();
429
430 $subtableByLabel = null;
431 if (!empty($dataArrayTwoLevels)) {
432 $subtableByLabel = array();
433 foreach ($dataArrayTwoLevels as $label => $subTable) {
434 $subtableByLabel[$label] = DataTable::makeFromIndexedArray($subTable);
435 }
436 }
437 return DataTable::makeFromIndexedArray($dataArray, $subtableByLabel);
438 }
439 }
440