PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/CustomVariables/CustomVariables.php

https://github.com/quarkness/piwik
PHP | 312 lines | 224 code | 38 blank | 50 comment | 27 complexity | c572ff02b1842a42c43a029106dab09d MD5 | raw file
  1. <?php
  2. /**
  3. * Piwik - Open source web analytics
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. * @version $Id$
  8. *
  9. * @category Piwik_Plugins
  10. * @package Piwik_CustomVariables
  11. */
  12. /**
  13. * @package Piwik_CustomVariables
  14. */
  15. class Piwik_CustomVariables extends Piwik_Plugin
  16. {
  17. public $archiveProcessing;
  18. protected $columnToSortByBeforeTruncation;
  19. protected $maximumRowsInDataTableLevelZero;
  20. protected $maximumRowsInSubDataTable;
  21. public function getInformation()
  22. {
  23. $info = array(
  24. 'description' => Piwik_Translate('CustomVariables_PluginDescription'),
  25. 'author' => 'Piwik',
  26. 'author_homepage' => 'http://piwik.org/',
  27. 'version' => Piwik_Version::VERSION,
  28. );
  29. return $info;
  30. }
  31. function getListHooksRegistered()
  32. {
  33. $hooks = array(
  34. 'ArchiveProcessing_Day.compute' => 'archiveDay',
  35. 'ArchiveProcessing_Period.compute' => 'archivePeriod',
  36. 'WidgetsList.add' => 'addWidgets',
  37. 'Menu.add' => 'addMenus',
  38. 'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
  39. 'API.getReportMetadata' => 'getReportMetadata',
  40. 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
  41. );
  42. return $hooks;
  43. }
  44. function addWidgets()
  45. {
  46. Piwik_AddWidget( 'General_Visitors', 'CustomVariables_CustomVariables', 'CustomVariables', 'getCustomVariables');
  47. }
  48. function addMenus()
  49. {
  50. Piwik_AddMenu('General_Visitors', 'CustomVariables_CustomVariables', array('module' => 'CustomVariables', 'action' => 'index'), $display = true, $order = 50);
  51. }
  52. public function getReportMetadata($notification)
  53. {
  54. $reports = &$notification->getNotificationObject();
  55. $reports = array_merge($reports, array(
  56. array(
  57. 'category' => Piwik_Translate('General_Visitors'),
  58. 'name' => Piwik_Translate('CustomVariables_CustomVariables'),
  59. 'module' => 'CustomVariables',
  60. 'action' => 'getCustomVariables',
  61. 'dimension' => Piwik_Translate('CustomVariables_ColumnCustomVariableName'),
  62. 'documentation' => Piwik_Translate('CustomVariables_CustomVariablesReportDocumentation', array('<br />', '<a href="http://piwik.org/docs/custom-variables/" target="_blank">', '</a>')),
  63. 'order' => 10
  64. ),
  65. ));
  66. }
  67. public function getSegmentsMetadata($notification)
  68. {
  69. $segments =& $notification->getNotificationObject();
  70. for($i=1; $i <= Piwik_Tracker::MAX_CUSTOM_VARIABLES; $i++)
  71. {
  72. $segments[] = array(
  73. 'type' => 'dimension',
  74. 'category' => 'CustomVariables_CustomVariables',
  75. 'name' => Piwik_Translate('CustomVariables_ColumnCustomVariableName').' '.$i
  76. .' ('.Piwik_Translate('CustomVariables_ScopeVisit').')',
  77. 'segment' => 'customVariableName'.$i,
  78. 'sqlSegment' => 'log_visit.custom_var_k'.$i,
  79. );
  80. $segments[] = array(
  81. 'type' => 'dimension',
  82. 'category' => 'CustomVariables_CustomVariables',
  83. 'name' => Piwik_Translate('CustomVariables_ColumnCustomVariableValue').' '.$i
  84. .' ('.Piwik_Translate('CustomVariables_ScopeVisit').')',
  85. 'segment' => 'customVariableValue'.$i,
  86. 'sqlSegment' => 'log_visit.custom_var_v'.$i,
  87. );
  88. $segments[] = array(
  89. 'type' => 'dimension',
  90. 'category' => 'CustomVariables_CustomVariables',
  91. 'name' => Piwik_Translate('CustomVariables_ColumnCustomVariableName').' '.$i
  92. .' ('.Piwik_Translate('CustomVariables_ScopePage').')',
  93. 'segment' => 'customVariablePageName'.$i,
  94. 'sqlSegment' => 'log_link_visit_action.custom_var_k'.$i,
  95. );
  96. $segments[] = array(
  97. 'type' => 'dimension',
  98. 'category' => 'CustomVariables_CustomVariables',
  99. 'name' => Piwik_Translate('CustomVariables_ColumnCustomVariableValue').' '.$i
  100. .' ('.Piwik_Translate('CustomVariables_ScopePage').')',
  101. 'segment' => 'customVariablePageValue'.$i,
  102. 'sqlSegment' => 'log_link_visit_action.custom_var_v'.$i,
  103. );
  104. }
  105. }
  106. /**
  107. * Adds Goal dimensions, so that the dimensions are displayed in the UI Goal Overview page
  108. */
  109. function getReportsWithGoalMetrics( $notification )
  110. {
  111. $dimensions =& $notification->getNotificationObject();
  112. $dimensions = array_merge($dimensions, array(
  113. array( 'category' => Piwik_Translate('General_Visit'),
  114. 'name' => Piwik_Translate('CustomVariables_CustomVariables'),
  115. 'module' => 'CustomVariables',
  116. 'action' => 'getCustomVariables',
  117. ),
  118. ));
  119. }
  120. function __construct()
  121. {
  122. $this->maximumRowsInDataTableLevelZero = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_referers;
  123. $this->maximumRowsInSubDataTable = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_subtable_referers;
  124. }
  125. protected $interestByCustomVariables = array();
  126. protected $interestByCustomVariablesAndValue = array();
  127. /**
  128. * Hooks on daily archive to trigger various log processing
  129. *
  130. * @param Piwik_Event_Notification $notification
  131. * @return void
  132. */
  133. public function archiveDay( $notification )
  134. {
  135. $this->interestByCustomVariables = $this->interestByCustomVariablesAndValue = array();
  136. /**
  137. * @var Piwik_ArchiveProcessing_Day
  138. */
  139. $this->archiveProcessing = $notification->getNotificationObject();
  140. if(!$this->archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
  141. $this->archiveDayAggregate($this->archiveProcessing);
  142. $this->archiveDayRecordInDatabase($this->archiveProcessing);
  143. destroy($this->interestByCustomVariables);
  144. destroy($this->interestByCustomVariablesAndValue);
  145. }
  146. const LABEL_CUSTOM_VALUE_NOT_DEFINED = "Value not defined";
  147. /**
  148. * @param Piwik_ArchiveProcessing_Day $archiveProcessing
  149. * @return void
  150. */
  151. protected function archiveDayAggregate(Piwik_ArchiveProcessing_Day $archiveProcessing)
  152. {
  153. for($i = 1; $i <= Piwik_Tracker::MAX_CUSTOM_VARIABLES; $i++ )
  154. {
  155. $keyField = "custom_var_k".$i;
  156. $valueField = "custom_var_v".$i;
  157. $dimensions = array($keyField, $valueField);
  158. $where = "%s.$keyField != ''";
  159. // Custom Vars names and values metrics for visits
  160. $query = $archiveProcessing->queryVisitsByDimension($dimensions, $where);
  161. while($row = $query->fetch() )
  162. {
  163. // Handle case custom var value is empty
  164. $row[$valueField] = $this->cleanCustomVarValue($row[$valueField]);
  165. // Aggregate
  166. if(!isset($this->interestByCustomVariables[$row[$keyField]])) $this->interestByCustomVariables[$row[$keyField]]= $archiveProcessing->getNewInterestRow();
  167. if(!isset($this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]])) $this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]] = $archiveProcessing->getNewInterestRow();
  168. $archiveProcessing->updateInterestStats( $row, $this->interestByCustomVariables[$row[$keyField]]);
  169. $archiveProcessing->updateInterestStats( $row, $this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]]);
  170. }
  171. // Custom Vars names and values metrics for page views
  172. $query = $archiveProcessing->queryActionsByDimension($dimensions, $where);
  173. $onlyMetricsAvailableInActionsTable = true;
  174. while($row = $query->fetch() )
  175. {
  176. // Handle case custom var value is empty
  177. $row[$valueField] = $this->cleanCustomVarValue($row[$valueField]);
  178. $label = $row[$valueField];
  179. // Remove price tracked if it's zero or we if we are not currently tracking an ecommerce var
  180. if(!in_array($row[$keyField], array('_pks', '_pkn', '_pkc')))
  181. {
  182. unset($row[Piwik_Archive::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED]);
  183. }
  184. // when custom variable value is a JSON array of categories
  185. // possibly JSON value
  186. $mustInsertCustomVariableValue = true;
  187. if($row[$keyField] == '_pkc'
  188. && $label[0] == '[' && $label[1] == '"')
  189. {
  190. // In case categories were truncated, try closing the array
  191. if(substr($label, -2) != '"]') {
  192. $label .= '"]';
  193. }
  194. $decoded = @Piwik_Common::json_decode($label);
  195. if(is_array($decoded))
  196. {
  197. $count = 0;
  198. foreach($decoded as $category)
  199. {
  200. if(empty($category)
  201. || $count >= Piwik_Tracker_GoalManager::MAXIMUM_PRODUCT_CATEGORIES) {
  202. continue;
  203. }
  204. if(!isset($this->interestByCustomVariablesAndValue[$row[$keyField]][$category])) {
  205. $this->interestByCustomVariablesAndValue[$row[$keyField]][$category] = $archiveProcessing->getNewInterestRow($onlyMetricsAvailableInActionsTable);
  206. }
  207. $archiveProcessing->updateInterestStats( $row, $this->interestByCustomVariablesAndValue[$row[$keyField]][$category], $onlyMetricsAvailableInActionsTable);
  208. $mustInsertCustomVariableValue = false;
  209. $count++;
  210. }
  211. }
  212. } // end multi categories hack
  213. if($mustInsertCustomVariableValue)
  214. {
  215. if(!isset($this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]])) $this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]] = $archiveProcessing->getNewInterestRow($onlyMetricsAvailableInActionsTable);
  216. $archiveProcessing->updateInterestStats( $row, $this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]], $onlyMetricsAvailableInActionsTable);
  217. }
  218. // Do not report on Price viewed for the Custom Variable names
  219. unset($row[Piwik_Archive::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED]);
  220. // When tracking Custom Variables with scope=page we do not add up visits numbers
  221. // as it is incorrect to sum visits this way
  222. // for scope=visit this is allowed, since there is supposed to be one custom var value per custom variable name for a given visit
  223. $doNotSumVisits = true;
  224. if(!isset($this->interestByCustomVariables[$row[$keyField]])) $this->interestByCustomVariables[$row[$keyField]]= $archiveProcessing->getNewInterestRow($onlyMetricsAvailableInActionsTable, $doNotSumVisits);
  225. $archiveProcessing->updateInterestStats( $row, $this->interestByCustomVariables[$row[$keyField]], $onlyMetricsAvailableInActionsTable, $doNotSumVisits);
  226. }
  227. // Custom Vars names and values metrics for Goals
  228. $query = $archiveProcessing->queryConversionsByDimension($dimensions, $where);
  229. if($query !== false)
  230. {
  231. while($row = $query->fetch() )
  232. {
  233. // Handle case custom var value is empty
  234. $row[$valueField] = $this->cleanCustomVarValue($row[$valueField]);
  235. if(!isset($this->interestByCustomVariables[$row[$keyField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCustomVariables[$row[$keyField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow($row['idgoal']);
  236. if(!isset($this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow($row['idgoal']);
  237. $archiveProcessing->updateGoalStats( $row, $this->interestByCustomVariables[$row[$keyField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
  238. $archiveProcessing->updateGoalStats( $row, $this->interestByCustomVariablesAndValue[$row[$keyField]][$row[$valueField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
  239. }
  240. }
  241. }
  242. $archiveProcessing->enrichConversionsByLabelArray($this->interestByCustomVariables);
  243. $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->interestByCustomVariablesAndValue);
  244. // var_dump($this->interestByCustomVariables);
  245. //var_dump($this->interestByCustomVariablesAndValue);
  246. }
  247. protected function cleanCustomVarValue($value)
  248. {
  249. if(!empty($value))
  250. {
  251. return $value;
  252. }
  253. return self::LABEL_CUSTOM_VALUE_NOT_DEFINED;
  254. }
  255. /**
  256. * @param Piwik_ArchiveProcessing $archiveProcessing
  257. * @return void
  258. */
  259. protected function archiveDayRecordInDatabase($archiveProcessing)
  260. {
  261. $recordName = 'CustomVariables_valueByName';
  262. $table = $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByCustomVariablesAndValue, $this->interestByCustomVariables);
  263. $blob = $table->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable);
  264. $archiveProcessing->insertBlobRecord($recordName, $blob);
  265. destroy($table);
  266. }
  267. function archivePeriod( $notification )
  268. {
  269. $archiveProcessing = $notification->getNotificationObject();
  270. if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
  271. $dataTableToSum = 'CustomVariables_valueByName';
  272. $nameToCount = $archiveProcessing->archiveDataTable($dataTableToSum, null, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable);
  273. }
  274. }