PageRenderTime 60ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/Events/Archiver.php

https://github.com/CodeYellowBV/piwik
PHP | 260 lines | 164 code | 31 blank | 65 comment | 11 complexity | 48aaafb6e044129e3a2d7228cc419d27 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\Events;
  10. use Piwik\Config;
  11. use Piwik\DataArray;
  12. use Piwik\DataTable;
  13. use Piwik\Metrics;
  14. use Piwik\Plugins\Actions\ArchivingHelper;
  15. use Piwik\RankingQuery;
  16. use Piwik\Tracker\Action;
  17. /**
  18. * Processing reports for Events
  19. EVENT
  20. - Category
  21. - Action
  22. - Name
  23. - Value
  24. METRICS (Events Overview report)
  25. - Total number of events
  26. - Unique events
  27. - Visits with events
  28. - Events/visit
  29. - Event value
  30. - Average event value AVG(custom_float)
  31. MAIN REPORTS:
  32. - Top Event Category (total events, unique events, event value, avg+min+max value)
  33. - Top Event Action (total events, unique events, event value, avg+min+max value)
  34. - Top Event Name (total events, unique events, event value, avg+min+max value)
  35. COMPOSED REPORTS
  36. - Top Category > Actions X
  37. - Top Category > Names X
  38. - Top Actions > Categories X
  39. - Top Actions > Names X
  40. - Top Names > Actions X
  41. - Top Names > Categories X
  42. UI
  43. - Overview at the top (graph + Sparklines)
  44. - Below show the left menu, defaults to Top Event Category
  45. Not MVP:
  46. - On hover on any row: Show % of total events
  47. - Add min value metric, max value metric in tooltip
  48. - List event scope Custom Variables Names > Custom variables values > Event Names > Event Actions
  49. - List event scope Custom Variables Value > Event Category > Event Names > Event Actions
  50. NOTES:
  51. - For a given Name, Category is often constant
  52. */
  53. class Archiver extends \Piwik\Plugin\Archiver
  54. {
  55. const EVENTS_CATEGORY_ACTION_RECORD_NAME = 'Events_category_action';
  56. const EVENTS_CATEGORY_NAME_RECORD_NAME = 'Events_category_name';
  57. const EVENTS_ACTION_CATEGORY_RECORD_NAME = 'Events_action_category';
  58. const EVENTS_ACTION_NAME_RECORD_NAME = 'Events_action_name';
  59. const EVENTS_NAME_ACTION_RECORD_NAME = 'Events_name_action';
  60. const EVENTS_NAME_CATEGORY_RECORD_NAME = 'Events_name_category';
  61. const EVENT_NAME_NOT_SET = 'Piwik_EventNameNotSet';
  62. /**
  63. * @var DataArray[]
  64. */
  65. protected $arrays = array();
  66. function __construct($processor)
  67. {
  68. parent::__construct($processor);
  69. $this->columnToSortByBeforeTruncation = Metrics::INDEX_NB_VISITS;
  70. $this->maximumRowsInDataTable = Config::getInstance()->General['datatable_archiving_maximum_rows_events'];
  71. $this->maximumRowsInSubDataTable = Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_events'];
  72. }
  73. protected function getRecordToDimensions()
  74. {
  75. return array(
  76. self::EVENTS_CATEGORY_ACTION_RECORD_NAME => array("eventCategory", "eventAction"),
  77. self::EVENTS_CATEGORY_NAME_RECORD_NAME => array("eventCategory", "eventName"),
  78. self::EVENTS_ACTION_NAME_RECORD_NAME => array("eventAction", "eventName"),
  79. self::EVENTS_ACTION_CATEGORY_RECORD_NAME => array("eventAction", "eventCategory"),
  80. self::EVENTS_NAME_ACTION_RECORD_NAME => array("eventName", "eventAction"),
  81. self::EVENTS_NAME_CATEGORY_RECORD_NAME => array("eventName", "eventCategory"),
  82. );
  83. }
  84. public function aggregateMultipleReports()
  85. {
  86. $dataTableToSum = $this->getRecordNames();
  87. $this->getProcessor()->aggregateDataTableRecords($dataTableToSum, $this->maximumRowsInDataTable, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation);
  88. }
  89. protected function getRecordNames()
  90. {
  91. $mapping = $this->getRecordToDimensions();
  92. return array_keys($mapping);
  93. }
  94. public function aggregateDayReport()
  95. {
  96. $this->aggregateDayEvents();
  97. $this->insertDayReports();
  98. }
  99. protected function aggregateDayEvents()
  100. {
  101. $select = "
  102. log_action_event_category.name as eventCategory,
  103. log_action_event_action.name as eventAction,
  104. log_action_event_name.name as eventName,
  105. count(distinct log_link_visit_action.idvisit) as `" . Metrics::INDEX_NB_VISITS . "`,
  106. count(distinct log_link_visit_action.idvisitor) as `" . Metrics::INDEX_NB_UNIQ_VISITORS . "`,
  107. count(*) as `" . Metrics::INDEX_EVENT_NB_HITS . "`,
  108. sum(
  109. case when " . Action::DB_COLUMN_CUSTOM_FLOAT . " is null
  110. then 0
  111. else " . Action::DB_COLUMN_CUSTOM_FLOAT . "
  112. end
  113. ) as `" . Metrics::INDEX_EVENT_SUM_EVENT_VALUE . "`,
  114. sum( case when " . Action::DB_COLUMN_CUSTOM_FLOAT . " is null then 0 else 1 end )
  115. as `" . Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE . "`,
  116. min(" . Action::DB_COLUMN_CUSTOM_FLOAT . ") as `" . Metrics::INDEX_EVENT_MIN_EVENT_VALUE . "`,
  117. max(" . Action::DB_COLUMN_CUSTOM_FLOAT . ") as `" . Metrics::INDEX_EVENT_MAX_EVENT_VALUE . "`
  118. ";
  119. $from = array(
  120. "log_link_visit_action",
  121. array(
  122. "table" => "log_action",
  123. "tableAlias" => "log_action_event_category",
  124. "joinOn" => "log_link_visit_action.idaction_event_category = log_action_event_category.idaction"
  125. ),
  126. array(
  127. "table" => "log_action",
  128. "tableAlias" => "log_action_event_action",
  129. "joinOn" => "log_link_visit_action.idaction_event_action = log_action_event_action.idaction"
  130. ),
  131. array(
  132. "table" => "log_action",
  133. "tableAlias" => "log_action_event_name",
  134. "joinOn" => "log_link_visit_action.idaction_name = log_action_event_name.idaction"
  135. )
  136. );
  137. $where = "log_link_visit_action.server_time >= ?
  138. AND log_link_visit_action.server_time <= ?
  139. AND log_link_visit_action.idsite = ?
  140. AND log_link_visit_action.idaction_event_category IS NOT NULL";
  141. $groupBy = "log_action_event_category.idaction,
  142. log_action_event_action.idaction,
  143. log_action_event_name.idaction";
  144. $orderBy = "`" . Metrics::INDEX_NB_VISITS . "` DESC";
  145. $rankingQueryLimit = ArchivingHelper::getRankingQueryLimit();
  146. $rankingQuery = null;
  147. if ($rankingQueryLimit > 0) {
  148. $rankingQuery = new RankingQuery($rankingQueryLimit);
  149. $rankingQuery->setOthersLabel(DataTable::LABEL_SUMMARY_ROW);
  150. $rankingQuery->addLabelColumn(array('eventCategory', 'eventAction', 'eventName'));
  151. $rankingQuery->addColumn(array(Metrics::INDEX_NB_UNIQ_VISITORS));
  152. $rankingQuery->addColumn(array(Metrics::INDEX_EVENT_NB_HITS, Metrics::INDEX_NB_VISITS, Metrics::INDEX_EVENT_NB_HITS_WITH_VALUE), 'sum');
  153. $rankingQuery->addColumn(Metrics::INDEX_EVENT_SUM_EVENT_VALUE, 'sum');
  154. $rankingQuery->addColumn(Metrics::INDEX_EVENT_MIN_EVENT_VALUE, 'min');
  155. $rankingQuery->addColumn(Metrics::INDEX_EVENT_MAX_EVENT_VALUE, 'max');
  156. }
  157. $this->archiveDayQueryProcess($select, $from, $where, $orderBy, $groupBy, $rankingQuery);
  158. }
  159. protected function archiveDayQueryProcess($select, $from, $where, $orderBy, $groupBy, RankingQuery $rankingQuery)
  160. {
  161. // get query with segmentation
  162. $query = $this->getLogAggregator()->generateQuery($select, $from, $where, $groupBy, $orderBy);
  163. // apply ranking query
  164. if ($rankingQuery) {
  165. $query['sql'] = $rankingQuery->generateQuery($query['sql']);
  166. }
  167. // get result
  168. $resultSet = $this->getLogAggregator()->getDb()->query($query['sql'], $query['bind']);
  169. if ($resultSet === false) {
  170. return;
  171. }
  172. while ($row = $resultSet->fetch()) {
  173. $this->aggregateEventRow($row);
  174. }
  175. }
  176. /**
  177. * Records the daily datatables
  178. */
  179. protected function insertDayReports()
  180. {
  181. foreach ($this->arrays as $recordName => $dataArray) {
  182. $dataTable = $dataArray->asDataTable();
  183. $blob = $dataTable->getSerialized(
  184. $this->maximumRowsInDataTable,
  185. $this->maximumRowsInSubDataTable,
  186. $this->columnToSortByBeforeTruncation);
  187. $this->getProcessor()->insertBlobRecord($recordName, $blob);
  188. }
  189. }
  190. /**
  191. * @param string $name
  192. * @return DataArray
  193. */
  194. protected function getDataArray($name)
  195. {
  196. if(empty($this->arrays[$name])) {
  197. $this->arrays[$name] = new DataArray();
  198. }
  199. return $this->arrays[$name];
  200. }
  201. protected function aggregateEventRow($row)
  202. {
  203. foreach ($this->getRecordToDimensions() as $record => $dimensions) {
  204. $dataArray = $this->getDataArray($record);
  205. $mainDimension = $dimensions[0];
  206. $mainLabel = $row[$mainDimension];
  207. // Event name is optional
  208. if ($mainDimension == 'eventName'
  209. && empty($mainLabel)) {
  210. $mainLabel = self::EVENT_NAME_NOT_SET;
  211. }
  212. $dataArray->sumMetricsEvents($mainLabel, $row);
  213. $subDimension = $dimensions[1];
  214. $subLabel = $row[$subDimension];
  215. if (empty($subLabel)) {
  216. continue;
  217. }
  218. $dataArray->sumMetricsEventsPivot($mainLabel, $subLabel, $row);
  219. }
  220. }
  221. }