PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Referrers/Archiver.php

https://github.com/CodeYellowBV/piwik
PHP | 269 lines | 209 code | 34 blank | 26 comment | 16 complexity | 7f19caa44ea8054954de2f45cfb85f0b 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\Referrers;
  10. use Exception;
  11. use Piwik\Common;
  12. use Piwik\Config;
  13. use Piwik\DataArray;
  14. use Piwik\Metrics;
  15. class Archiver extends \Piwik\Plugin\Archiver
  16. {
  17. const SEARCH_ENGINES_RECORD_NAME = 'Referrers_keywordBySearchEngine';
  18. const KEYWORDS_RECORD_NAME = 'Referrers_searchEngineByKeyword';
  19. const CAMPAIGNS_RECORD_NAME = 'Referrers_keywordByCampaign';
  20. const WEBSITES_RECORD_NAME = 'Referrers_urlByWebsite';
  21. const REFERRER_TYPE_RECORD_NAME = 'Referrers_type';
  22. const METRIC_DISTINCT_SEARCH_ENGINE_RECORD_NAME = 'Referrers_distinctSearchEngines';
  23. const METRIC_DISTINCT_KEYWORD_RECORD_NAME = 'Referrers_distinctKeywords';
  24. const METRIC_DISTINCT_CAMPAIGN_RECORD_NAME = 'Referrers_distinctCampaigns';
  25. const METRIC_DISTINCT_WEBSITE_RECORD_NAME = 'Referrers_distinctWebsites';
  26. const METRIC_DISTINCT_URLS_RECORD_NAME = 'Referrers_distinctWebsitesUrls';
  27. protected $columnToSortByBeforeTruncation;
  28. protected $maximumRowsInDataTableLevelZero;
  29. protected $maximumRowsInSubDataTable;
  30. /**
  31. * @var DataArray[] $arrays
  32. */
  33. protected $arrays = array();
  34. protected $distinctUrls = array();
  35. function __construct($processor)
  36. {
  37. parent::__construct($processor);
  38. $this->columnToSortByBeforeTruncation = Metrics::INDEX_NB_VISITS;
  39. // Reading pre 2.0 config file settings
  40. $this->maximumRowsInDataTableLevelZero = @Config::getInstance()->General['datatable_archiving_maximum_rows_referers'];
  41. $this->maximumRowsInSubDataTable = @Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_referers'];
  42. if (empty($this->maximumRowsInDataTableLevelZero)) {
  43. $this->maximumRowsInDataTableLevelZero = Config::getInstance()->General['datatable_archiving_maximum_rows_referrers'];
  44. $this->maximumRowsInSubDataTable = Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_referrers'];
  45. }
  46. }
  47. public function aggregateDayReport()
  48. {
  49. foreach ($this->getRecordNames() as $record) {
  50. $this->arrays[$record] = new DataArray();
  51. }
  52. $this->aggregateFromVisits(array("referer_type", "referer_name", "referer_keyword", "referer_url"));
  53. $this->aggregateFromConversions(array("referer_type", "referer_name", "referer_keyword"));
  54. $this->insertDayReports();
  55. }
  56. protected function getRecordNames()
  57. {
  58. return array(
  59. self::REFERRER_TYPE_RECORD_NAME,
  60. self::KEYWORDS_RECORD_NAME,
  61. self::SEARCH_ENGINES_RECORD_NAME,
  62. self::WEBSITES_RECORD_NAME,
  63. self::CAMPAIGNS_RECORD_NAME,
  64. );
  65. }
  66. protected function makeReferrerTypeNonEmpty(&$row)
  67. {
  68. if (empty($row['referer_type'])) {
  69. $row['referer_type'] = Common::REFERRER_TYPE_DIRECT_ENTRY;
  70. }
  71. }
  72. protected function aggregateVisitRow($row)
  73. {
  74. switch ($row['referer_type']) {
  75. case Common::REFERRER_TYPE_SEARCH_ENGINE:
  76. if (empty($row['referer_keyword'])) {
  77. $row['referer_keyword'] = API::LABEL_KEYWORD_NOT_DEFINED;
  78. }
  79. $searchEnginesArray = $this->getDataArray(self::SEARCH_ENGINES_RECORD_NAME);
  80. $searchEnginesArray->sumMetricsVisits($row['referer_name'], $row);
  81. $searchEnginesArray->sumMetricsVisitsPivot($row['referer_name'], $row['referer_keyword'], $row);
  82. $keywordsDataArray = $this->getDataArray(self::KEYWORDS_RECORD_NAME);
  83. $keywordsDataArray->sumMetricsVisits($row['referer_keyword'], $row);
  84. $keywordsDataArray->sumMetricsVisitsPivot($row['referer_keyword'], $row['referer_name'], $row);
  85. break;
  86. case Common::REFERRER_TYPE_WEBSITE:
  87. $this->getDataArray(self::WEBSITES_RECORD_NAME)->sumMetricsVisits($row['referer_name'], $row);
  88. $this->getDataArray(self::WEBSITES_RECORD_NAME)->sumMetricsVisitsPivot($row['referer_name'], $row['referer_url'], $row);
  89. $urlHash = substr(md5($row['referer_url']), 0, 10);
  90. if (!isset($this->distinctUrls[$urlHash])) {
  91. $this->distinctUrls[$urlHash] = true;
  92. }
  93. break;
  94. case Common::REFERRER_TYPE_CAMPAIGN:
  95. if (!empty($row['referer_keyword'])) {
  96. $this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsVisitsPivot($row['referer_name'], $row['referer_keyword'], $row);
  97. }
  98. $this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsVisits($row['referer_name'], $row);
  99. break;
  100. case Common::REFERRER_TYPE_DIRECT_ENTRY:
  101. // direct entry are aggregated below in $this->metricsByType array
  102. break;
  103. default:
  104. throw new Exception("Non expected referer_type = " . $row['referer_type']);
  105. break;
  106. }
  107. $this->getDataArray(self::REFERRER_TYPE_RECORD_NAME)->sumMetricsVisits($row['referer_type'], $row);
  108. }
  109. /**
  110. * @param string $name
  111. * @return DataArray
  112. */
  113. protected function getDataArray($name)
  114. {
  115. return $this->arrays[$name];
  116. }
  117. protected function aggregateFromConversions($dimensions)
  118. {
  119. $query = $this->getLogAggregator()->queryConversionsByDimension($dimensions);
  120. if ($query === false) {
  121. return;
  122. }
  123. while ($row = $query->fetch()) {
  124. $this->makeReferrerTypeNonEmpty($row);
  125. $skipAggregateByType = $this->aggregateConversionRow($row);
  126. if (!$skipAggregateByType) {
  127. $this->getDataArray(self::REFERRER_TYPE_RECORD_NAME)->sumMetricsGoals($row['referer_type'], $row);
  128. }
  129. }
  130. foreach ($this->arrays as $dataArray) {
  131. $dataArray->enrichMetricsWithConversions();
  132. }
  133. }
  134. protected function aggregateConversionRow($row)
  135. {
  136. $skipAggregateByType = false;
  137. switch ($row['referer_type']) {
  138. case Common::REFERRER_TYPE_SEARCH_ENGINE:
  139. if (empty($row['referer_keyword'])) {
  140. $row['referer_keyword'] = API::LABEL_KEYWORD_NOT_DEFINED;
  141. }
  142. $this->getDataArray(self::SEARCH_ENGINES_RECORD_NAME)->sumMetricsGoals($row['referer_name'], $row);
  143. $this->getDataArray(self::KEYWORDS_RECORD_NAME)->sumMetricsGoals($row['referer_keyword'], $row);
  144. break;
  145. case Common::REFERRER_TYPE_WEBSITE:
  146. $this->getDataArray(self::WEBSITES_RECORD_NAME)->sumMetricsGoals($row['referer_name'], $row);
  147. break;
  148. case Common::REFERRER_TYPE_CAMPAIGN:
  149. if (!empty($row['referer_keyword'])) {
  150. $this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsGoalsPivot($row['referer_name'], $row['referer_keyword'], $row);
  151. }
  152. $this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsGoals($row['referer_name'], $row);
  153. break;
  154. case Common::REFERRER_TYPE_DIRECT_ENTRY:
  155. // Direct entry, no sub dimension
  156. break;
  157. default:
  158. // The referer type is user submitted for goal conversions, we ignore any malformed value
  159. // Continue to the next while iteration
  160. $skipAggregateByType = true;
  161. break;
  162. }
  163. return $skipAggregateByType;
  164. }
  165. /**
  166. * Records the daily stats (numeric or datatable blob) into the archive tables.
  167. */
  168. protected function insertDayReports()
  169. {
  170. $this->insertDayNumericMetrics();
  171. // insert DataTable reports
  172. foreach ($this->getRecordNames() as $recordName) {
  173. $blob = $this->getDataArray($recordName)->asDataTable()->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation);
  174. $this->getProcessor()->insertBlobRecord($recordName, $blob);
  175. }
  176. }
  177. protected function insertDayNumericMetrics()
  178. {
  179. $numericRecords = array(
  180. self::METRIC_DISTINCT_SEARCH_ENGINE_RECORD_NAME => count($this->getDataArray(self::SEARCH_ENGINES_RECORD_NAME)),
  181. self::METRIC_DISTINCT_KEYWORD_RECORD_NAME => count($this->getDataArray(self::KEYWORDS_RECORD_NAME)),
  182. self::METRIC_DISTINCT_CAMPAIGN_RECORD_NAME => count($this->getDataArray(self::CAMPAIGNS_RECORD_NAME)),
  183. self::METRIC_DISTINCT_WEBSITE_RECORD_NAME => count($this->getDataArray(self::WEBSITES_RECORD_NAME)),
  184. self::METRIC_DISTINCT_URLS_RECORD_NAME => count($this->distinctUrls),
  185. );
  186. $this->getProcessor()->insertNumericRecords($numericRecords);
  187. }
  188. public function aggregateMultipleReports()
  189. {
  190. $dataTableToSum = $this->getRecordNames();
  191. $nameToCount = $this->getProcessor()->aggregateDataTableRecords($dataTableToSum, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation);
  192. $mappingFromArchiveName = array(
  193. self::METRIC_DISTINCT_SEARCH_ENGINE_RECORD_NAME =>
  194. array('typeCountToUse' => 'level0',
  195. 'nameTableToUse' => self::SEARCH_ENGINES_RECORD_NAME,
  196. ),
  197. self::METRIC_DISTINCT_KEYWORD_RECORD_NAME =>
  198. array('typeCountToUse' => 'level0',
  199. 'nameTableToUse' => self::KEYWORDS_RECORD_NAME,
  200. ),
  201. self::METRIC_DISTINCT_CAMPAIGN_RECORD_NAME =>
  202. array('typeCountToUse' => 'level0',
  203. 'nameTableToUse' => self::CAMPAIGNS_RECORD_NAME,
  204. ),
  205. self::METRIC_DISTINCT_WEBSITE_RECORD_NAME =>
  206. array('typeCountToUse' => 'level0',
  207. 'nameTableToUse' => self::WEBSITES_RECORD_NAME,
  208. ),
  209. self::METRIC_DISTINCT_URLS_RECORD_NAME =>
  210. array('typeCountToUse' => 'recursive',
  211. 'nameTableToUse' => self::WEBSITES_RECORD_NAME,
  212. ),
  213. );
  214. foreach ($mappingFromArchiveName as $name => $infoMapping) {
  215. $nameTableToUse = $infoMapping['nameTableToUse'];
  216. if ($infoMapping['typeCountToUse'] == 'recursive') {
  217. $countValue = $nameToCount[$nameTableToUse]['recursive'] - $nameToCount[$nameTableToUse]['level0'];
  218. } else {
  219. $countValue = $nameToCount[$nameTableToUse]['level0'];
  220. }
  221. $this->getProcessor()->insertNumericRecord($name, $countValue);
  222. }
  223. }
  224. /**
  225. * @param $fields
  226. */
  227. private function aggregateFromVisits($fields)
  228. {
  229. $query = $this->getLogAggregator()->queryVisitsByDimension($fields);
  230. while ($row = $query->fetch()) {
  231. $this->makeReferrerTypeNonEmpty($row);
  232. $this->aggregateVisitRow($row);
  233. }
  234. }
  235. }