PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Insights/InsightReport.php

https://github.com/CodeYellowBV/piwik
PHP | 288 lines | 192 code | 36 blank | 60 comment | 18 complexity | ae427f0dbf5e4712ada47bc1e592b76c MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik\Plugins\Insights;
  10. use Piwik\DataTable;
  11. use Piwik\Piwik;
  12. /**
  13. * Insight report generator
  14. */
  15. class InsightReport
  16. {
  17. const ORDER_BY_RELATIVE = 'relative';
  18. const ORDER_BY_ABSOLUTE = 'absolute';
  19. const ORDER_BY_IMPORTANCE = 'importance';
  20. /**
  21. * @param array $reportMetadata
  22. * @param string $period
  23. * @param string $date
  24. * @param string $lastDate
  25. * @param string $metric
  26. * @param DataTable $currentReport
  27. * @param DataTable $lastReport
  28. * @param int $totalValue
  29. * @param int $lastTotalValue
  30. * @param string $orderBy
  31. * @param int $limitIncreaser
  32. * @param int $limitDecreaser
  33. * @return DataTable
  34. */
  35. public function generateMoverAndShaker($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $lastTotalValue, $orderBy, $limitIncreaser, $limitDecreaser)
  36. {
  37. $totalEvolution = $this->getTotalEvolution($totalValue, $lastTotalValue);
  38. $minMoversPercent = 1;
  39. if ($totalEvolution >= 100) {
  40. // eg change from 50 to 150 = 200%
  41. $factor = (int) ceil($totalEvolution / 500);
  42. $minGrowthPercentPositive = $totalEvolution + ($factor * 40); // min +240%
  43. $minGrowthPercentNegative = -70; // min -70%
  44. $minDisappearedPercent = 8; // min 12
  45. $minNewPercent = min(($totalEvolution / 100) * 3, 10); // min 6% = min 10 of total visits up to max 10%
  46. } elseif ($totalEvolution >= 0) {
  47. // eg change from 50 to 75 = 50%
  48. $minGrowthPercentPositive = $totalEvolution + 20; // min 70%
  49. $minGrowthPercentNegative = -1 * $minGrowthPercentPositive; // min -70%
  50. $minDisappearedPercent = 7;
  51. $minNewPercent = 5;
  52. } else {
  53. // eg change from 50 to 25 = -50%
  54. $minGrowthPercentNegative = $totalEvolution - 20; // min -70%
  55. $minGrowthPercentPositive = abs($minGrowthPercentNegative); // min 70%
  56. $minDisappearedPercent = 7;
  57. $minNewPercent = 5;
  58. }
  59. if ($totalValue < 200 && $totalValue != 0) {
  60. // force at least a change of 2 visits
  61. $minMoversPercent = (int) ceil(2 / ($totalValue / 100));
  62. $minNewPercent = max($minNewPercent, $minMoversPercent);
  63. $minDisappearedPercent = max($minDisappearedPercent, $minMoversPercent);
  64. }
  65. $dataTable = $this->generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser);
  66. $this->addMoversAndShakersMetadata($dataTable, $totalValue, $lastTotalValue);
  67. return $dataTable;
  68. }
  69. /**
  70. * Extends an already generated insight report by adding a column "isMoverAndShaker" whether a row is also a
  71. * "Mover and Shaker" or not.
  72. *
  73. * Avoids the need to fetch all reports again when we already have the currentReport/lastReport
  74. */
  75. public function markMoversAndShakers(DataTable $insight, $currentReport, $lastReport, $totalValue, $lastTotalValue)
  76. {
  77. if (!$insight->getRowsCount()) {
  78. return;
  79. }
  80. $limitIncreaser = max($insight->getRowsCount(), 3);
  81. $limitDecreaser = max($insight->getRowsCount(), 3);
  82. $lastDate = $insight->getMetadata('lastDate');
  83. $date = $insight->getMetadata('date');
  84. $period = $insight->getMetadata('period');
  85. $metric = $insight->getMetadata('metric');
  86. $orderBy = $insight->getMetadata('orderBy');
  87. $reportMetadata = $insight->getMetadata('report');
  88. $shakers = $this->generateMoverAndShaker($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $lastTotalValue, $orderBy, $limitIncreaser, $limitDecreaser);
  89. foreach ($insight->getRows() as $row) {
  90. $label = $row->getColumn('label');
  91. if ($shakers->getRowFromLabel($label)) {
  92. $row->setColumn('isMoverAndShaker', true);
  93. } else {
  94. $row->setColumn('isMoverAndShaker', false);
  95. }
  96. }
  97. $this->addMoversAndShakersMetadata($insight, $totalValue, $lastTotalValue);
  98. }
  99. /**
  100. * @param array $reportMetadata
  101. * @param string $period
  102. * @param string $date
  103. * @param string $lastDate
  104. * @param string $metric
  105. * @param DataTable $currentReport
  106. * @param DataTable $lastReport
  107. * @param int $totalValue
  108. * @param int $minMoversPercent Exclude rows who moved and the difference is not at least min percent
  109. * visits of totalVisits. -1 excludes movers.
  110. * @param int $minNewPercent Exclude rows who are new and the difference is not at least min percent
  111. * visits of totalVisits. -1 excludes all new.
  112. * @param int $minDisappearedPercent Exclude rows who are disappeared and the difference is not at least min
  113. * percent visits of totalVisits. -1 excludes all disappeared.
  114. * @param int $minGrowthPercentPositive The actual growth of a row must be at least percent compared to the
  115. * previous value (not total value)
  116. * @param int $minGrowthPercentNegative The actual growth of a row must be lower percent compared to the
  117. * previous value (not total value)
  118. * @param string $orderBy Order by absolute, relative, importance
  119. * @param int $limitIncreaser
  120. * @param int $limitDecreaser
  121. *
  122. * @return DataTable
  123. */
  124. public function generateInsight($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercentPositive, $minGrowthPercentNegative, $orderBy, $limitIncreaser, $limitDecreaser)
  125. {
  126. $minChangeMovers = $this->getMinVisits($totalValue, $minMoversPercent);
  127. $minIncreaseNew = $this->getMinVisits($totalValue, $minNewPercent);
  128. $minDecreaseDisappeared = $this->getMinVisits($totalValue, $minDisappearedPercent);
  129. $dataTable = new DataTable();
  130. $dataTable->filter(
  131. 'Piwik\Plugins\Insights\DataTable\Filter\Insight',
  132. array(
  133. $currentReport,
  134. $lastReport,
  135. $metric,
  136. $considerMovers = (-1 !== $minMoversPercent),
  137. $considerNew = (-1 !== $minNewPercent),
  138. $considerDisappeared = (-1 !== $minDisappearedPercent)
  139. )
  140. );
  141. $dataTable->filter(
  142. 'Piwik\Plugins\Insights\DataTable\Filter\MinGrowth',
  143. array(
  144. 'growth_percent_numeric',
  145. $minGrowthPercentPositive,
  146. $minGrowthPercentNegative
  147. )
  148. );
  149. if ($minIncreaseNew) {
  150. $dataTable->filter(
  151. 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
  152. array(
  153. 'difference',
  154. $minIncreaseNew,
  155. 'isNew'
  156. )
  157. );
  158. }
  159. if ($minChangeMovers) {
  160. $dataTable->filter(
  161. 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
  162. array(
  163. 'difference',
  164. $minChangeMovers,
  165. 'isMover'
  166. )
  167. );
  168. }
  169. if ($minDecreaseDisappeared) {
  170. $dataTable->filter(
  171. 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue',
  172. array(
  173. 'difference',
  174. $minDecreaseDisappeared,
  175. 'isDisappeared'
  176. )
  177. );
  178. }
  179. $dataTable->filter(
  180. 'Piwik\Plugins\Insights\DataTable\Filter\OrderBy',
  181. array(
  182. $this->getOrderByColumn($orderBy),
  183. $orderBy === self::ORDER_BY_RELATIVE ? $this->getOrderByColumn(self::ORDER_BY_ABSOLUTE) : $this->getOrderByColumn(self::ORDER_BY_RELATIVE),
  184. $metric
  185. )
  186. );
  187. $dataTable->filter(
  188. 'Piwik\Plugins\Insights\DataTable\Filter\Limit',
  189. array(
  190. 'growth_percent_numeric',
  191. $limitIncreaser,
  192. $limitDecreaser
  193. )
  194. );
  195. $metricName = $metric;
  196. if (!empty($reportMetadata['metrics'][$metric])) {
  197. $metricName = $reportMetadata['metrics'][$metric];
  198. }
  199. $dataTable->setMetadataValues(array(
  200. 'reportName' => $reportMetadata['name'],
  201. 'metricName' => $metricName,
  202. 'date' => $date,
  203. 'lastDate' => $lastDate,
  204. 'period' => $period,
  205. 'report' => $reportMetadata,
  206. 'totalValue' => $totalValue,
  207. 'orderBy' => $orderBy,
  208. 'metric' => $metric,
  209. 'minChangeMovers' => $minChangeMovers,
  210. 'minIncreaseNew' => $minIncreaseNew,
  211. 'minDecreaseDisappeared' => $minDecreaseDisappeared,
  212. 'minGrowthPercentPositive' => $minGrowthPercentPositive,
  213. 'minGrowthPercentNegative' => $minGrowthPercentNegative,
  214. 'minMoversPercent' => $minMoversPercent,
  215. 'minNewPercent' => $minNewPercent,
  216. 'minDisappearedPercent' => $minDisappearedPercent
  217. ));
  218. return $dataTable;
  219. }
  220. private function getOrderByColumn($orderBy)
  221. {
  222. if (self::ORDER_BY_RELATIVE == $orderBy) {
  223. $orderByColumn = 'growth_percent_numeric';
  224. } elseif (self::ORDER_BY_ABSOLUTE == $orderBy) {
  225. $orderByColumn = 'difference';
  226. } elseif (self::ORDER_BY_IMPORTANCE == $orderBy) {
  227. $orderByColumn = 'importance';
  228. } else {
  229. throw new \Exception('Unsupported orderBy');
  230. }
  231. return $orderByColumn;
  232. }
  233. private function getMinVisits($totalValue, $percent)
  234. {
  235. if ($percent <= 0) {
  236. return 0;
  237. }
  238. $minVisits = ceil(($totalValue / 100) * $percent);
  239. return (int) $minVisits;
  240. }
  241. private function addMoversAndShakersMetadata(DataTable $dataTable, $totalValue, $lastTotalValue)
  242. {
  243. $totalEvolution = $this->getTotalEvolution($totalValue, $lastTotalValue);
  244. $dataTable->setMetadata('lastTotalValue', $lastTotalValue);
  245. $dataTable->setMetadata('evolutionTotal', $totalEvolution);
  246. $dataTable->setMetadata('evolutionDifference', $totalValue - $lastTotalValue);
  247. }
  248. private function getTotalEvolution($totalValue, $lastTotalValue)
  249. {
  250. return Piwik::getPercentageSafe($totalValue - $lastTotalValue, $lastTotalValue, 1);
  251. }
  252. }