diff --git a/plugins/CustomVariables/Archiving.php b/plugins/CustomVariables/Archiving.php index 166d8c912480a6c283296bcf3888d59f1d4d96a3..c85d230b3b41e84dc459b8b16f988e5d8c5065a5 100644 --- a/plugins/CustomVariables/Archiving.php +++ b/plugins/CustomVariables/Archiving.php @@ -27,10 +27,15 @@ class Piwik_CustomVariables_Archiving public function archiveDay(Piwik_ArchiveProcessing_Day $archiveProcessing) { - $this->archiveDayAggregate($archiveProcessing); + for ($i = 1; $i <= Piwik_Tracker::MAX_CUSTOM_VARIABLES; $i++) { + $this->aggregateCustomVariable($archiveProcessing, $i); + } - $table = $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByKeyAndValue, $this->metricsByKey); + $this->removeVisitsMetricsFromActionsAggregate($archiveProcessing); + $archiveProcessing->enrichConversionsByLabelArray($this->metricsByKey); + $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->metricsByKeyAndValue); + $table = $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByKeyAndValue, $this->metricsByKey); $blob = $table->getSerialized( $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $columnToSort = Piwik_Archive::INDEX_NB_VISITS @@ -39,21 +44,6 @@ class Piwik_CustomVariables_Archiving $archiveProcessing->insertBlobRecord(self::BLOB_NAME, $blob); } - /** - * @param Piwik_ArchiveProcessing_Day $archiveProcessing - * @return void - */ - protected function archiveDayAggregate(Piwik_ArchiveProcessing_Day $archiveProcessing) - { - for ($i = 1; $i <= Piwik_Tracker::MAX_CUSTOM_VARIABLES; $i++) { - $this->aggregateCustomVariable($archiveProcessing, $i); - } - - $this->removeVisitsMetricsFromActionsAggregate($archiveProcessing); - $archiveProcessing->enrichConversionsByLabelArray($this->metricsByKey); - $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->metricsByKeyAndValue); - } - /** * @param Piwik_ArchiveProcessing_Day $archiveProcessing * @param $slot diff --git a/plugins/Goals/Archiving.php b/plugins/Goals/Archiving.php new file mode 100644 index 0000000000000000000000000000000000000000..c99ba4d48d7942f739042252245f1d81807f0de5 --- /dev/null +++ b/plugins/Goals/Archiving.php @@ -0,0 +1,346 @@ +<?php + +class Piwik_Goals_Archiving +{ + + const VISITS_UNTIL_RECORD_NAME = 'visits_until_conv'; + const DAYS_UNTIL_CONV_RECORD_NAME = 'days_until_conv'; + /** + * This array stores the ranges to use when displaying the 'visits to conversion' report + */ + public static $visitCountRanges = array( + array(1, 1), + array(2, 2), + array(3, 3), + array(4, 4), + array(5, 5), + array(6, 6), + array(7, 7), + array(8, 8), + array(9, 14), + array(15, 25), + array(26, 50), + array(51, 100), + array(100) + ); + /** + * This array stores the ranges to use when displaying the 'days to conversion' report + */ + public static $daysToConvRanges = array( + array(0, 0), + array(1, 1), + array(2, 2), + array(3, 3), + array(4, 4), + array(5, 5), + array(6, 6), + array(7, 7), + array(8, 14), + array(15, 30), + array(31, 60), + array(61, 120), + array(121, 364), + array(364) + ); + protected $dimensions = array( + 'idaction_sku' => 'Goals_ItemsSku', + 'idaction_name' => 'Goals_ItemsName', + 'idaction_category' => 'Goals_ItemsCategory' + ); + + /** + * @param $archiveProcessing + */ + public function archiveDay($archiveProcessing) + { + $this->archiveGeneralGoalMetrics($archiveProcessing); + $this->archiveEcommerceItems($archiveProcessing); + } + + /** + * @param Piwik_ArchiveProcessing_Day $archiveProcessing + */ + function archiveGeneralGoalMetrics($archiveProcessing) + { + // extra aggregate selects for the visits to conversion report + $visitToConvExtraCols = Piwik_ArchiveProcessing_Day::buildReduceByRangeSelect( + 'visitor_count_visits', self::$visitCountRanges, 'log_conversion', 'vcv'); + + // extra aggregate selects for the days to conversion report + $daysToConvExtraCols = Piwik_ArchiveProcessing_Day::buildReduceByRangeSelect( + 'visitor_days_since_first', self::$daysToConvRanges, 'log_conversion', 'vdsf'); + + $query = $archiveProcessing->queryConversionsByDimension( + array(), '', array_merge($visitToConvExtraCols, $daysToConvExtraCols)); + + if ($query === false) { + return; + } + + $goals = array(); + $visitsToConvReport = array(); + $daysToConvReport = array(); + + // Get a standard empty goal row + $overall = $archiveProcessing->makeEmptyGoalRow($idGoal = 1); + while ($row = $query->fetch()) { + $idgoal = $row['idgoal']; + + if (!isset($goals[$idgoal])) { + $goals[$idgoal] = $archiveProcessing->makeEmptyGoalRow($idgoal); + + $visitsToConvReport[$idgoal] = new Piwik_DataTable(); + $daysToConvReport[$idgoal] = new Piwik_DataTable(); + } + $archiveProcessing->sumGoalMetrics($row, $goals[$idgoal]); + + // We don't want to sum Abandoned cart metrics in the overall revenue/conversions/converted visits + // since it is a "negative conversion" + if ($idgoal != Piwik_Tracker_GoalManager::IDGOAL_CART) { + $archiveProcessing->sumGoalMetrics($row, $overall); + } + + // map the goal + visit number of a visitor with the # of conversions that happened on that visit + $table = $archiveProcessing->getSimpleDataTableFromRow($row, Piwik_Archive::INDEX_NB_CONVERSIONS, 'vcv'); + $visitsToConvReport[$idgoal]->addDataTable($table); + + // map the goal + day number of a visit with the # of conversion that happened on that day + $table = $archiveProcessing->getSimpleDataTableFromRow($row, Piwik_Archive::INDEX_NB_CONVERSIONS, 'vdsf'); + $daysToConvReport[$idgoal]->addDataTable($table); + } + + // these data tables hold reports for every goal of a site + $visitsToConvOverview = new Piwik_DataTable(); + $daysToConvOverview = new Piwik_DataTable(); + + // Stats by goal, for all visitors + foreach ($goals as $idgoal => $values) { + foreach ($values as $metricId => $value) { + $metricName = Piwik_Archive::$mappingFromIdToNameGoal[$metricId]; + $recordName = self::getRecordName($metricName, $idgoal); + $archiveProcessing->insertNumericRecord($recordName, $value); + } + $conversion_rate = $this->getConversionRate($values[Piwik_Archive::INDEX_GOAL_NB_VISITS_CONVERTED], $archiveProcessing); + $recordName = self::getRecordName('conversion_rate', $idgoal); + $archiveProcessing->insertNumericRecord($recordName, $conversion_rate); + + // if the goal is not a special goal (like ecommerce) add it to the overview report + if ($idgoal !== Piwik_Tracker_GoalManager::IDGOAL_CART && + $idgoal !== Piwik_Tracker_GoalManager::IDGOAL_ORDER + ) { + $visitsToConvOverview->addDataTable($visitsToConvReport[$idgoal]); + $daysToConvOverview->addDataTable($daysToConvReport[$idgoal]); + } + + // visit count until conversion stats + $archiveProcessing->insertBlobRecord( + self::getRecordName(self::VISITS_UNTIL_RECORD_NAME, $idgoal), + $visitsToConvReport[$idgoal]->getSerialized()); + + // day count until conversion stats + $archiveProcessing->insertBlobRecord( + self::getRecordName(self::DAYS_UNTIL_CONV_RECORD_NAME, $idgoal), + $daysToConvReport[$idgoal]->getSerialized()); + } + + // archive overview reports + $archiveProcessing->insertBlobRecord( + self::getRecordName(self::VISITS_UNTIL_RECORD_NAME), $visitsToConvOverview->getSerialized()); + $archiveProcessing->insertBlobRecord( + self::getRecordName(self::DAYS_UNTIL_CONV_RECORD_NAME), $daysToConvOverview->getSerialized()); + + // Stats for all goals + $totalAllGoals = array( + self::getRecordName('conversion_rate') => $this->getConversionRate($archiveProcessing->getNumberOfVisitsConverted(), $archiveProcessing), + self::getRecordName('nb_conversions') => $overall[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS], + self::getRecordName('nb_visits_converted') => $archiveProcessing->getNumberOfVisitsConverted(), + self::getRecordName('revenue') => $overall[Piwik_Archive::INDEX_GOAL_REVENUE], + ); + foreach ($totalAllGoals as $recordName => $value) { + $archiveProcessing->insertNumericRecord($recordName, $value); + } + } + + /** + * @param string $recordName 'nb_conversions' + * @param int|bool $idGoal idGoal to return the metrics for, or false to return overall + * @return string Archive record name + */ + static public function getRecordName($recordName, $idGoal = false) + { + $idGoalStr = ''; + if ($idGoal !== false) { + $idGoalStr = $idGoal . "_"; + } + return 'Goal_' . $idGoalStr . $recordName; + } + + private function getConversionRate($count, $archiveProcessing) + { + $visits = $archiveProcessing->getNumberOfVisits(); + return round(100 * $count / $visits, Piwik_Tracker_GoalManager::REVENUE_PRECISION); + } + + /** + * @param Piwik_ArchiveProcessing_Day $archiveProcessing + */ + function archiveEcommerceItems($archiveProcessing) + { + if (!$this->shouldArchiveEcommerceItems($archiveProcessing)) { + return false; + } + $items = array(); + + $dimensionsToQuery = $this->dimensions; + $dimensionsToQuery['idaction_category2'] = 'AdditionalCategory'; + $dimensionsToQuery['idaction_category3'] = 'AdditionalCategory'; + $dimensionsToQuery['idaction_category4'] = 'AdditionalCategory'; + $dimensionsToQuery['idaction_category5'] = 'AdditionalCategory'; + + foreach ($dimensionsToQuery as $dimension => $recordName) { + $query = $archiveProcessing->queryEcommerceItems($dimension); + if ($query == false) { + continue; + } + + while ($row = $query->fetch()) { + $label = $row['label']; + $ecommerceType = $row['ecommerceType']; + + if (empty($label)) { + // idaction==0 case: + // If we are querying any optional category, we do not include idaction=0 + // Otherwise we over-report in the Product Categories report + if ($recordName == 'AdditionalCategory') { + continue; + } + // Product Name/Category not defined" + if (class_exists('Piwik_CustomVariables')) { + $label = Piwik_CustomVariables_Archiving::LABEL_CUSTOM_VALUE_NOT_DEFINED; + } else { + $label = "Value not defined"; + } + } + // For carts, idorder = 0. To count abandoned carts, we must count visits with an abandoned cart + if ($ecommerceType == Piwik_Tracker_GoalManager::IDGOAL_CART) { + $row[Piwik_Archive::INDEX_ECOMMERCE_ORDERS] = $row[Piwik_Archive::INDEX_NB_VISITS]; + } + unset($row[Piwik_Archive::INDEX_NB_VISITS]); + unset($row['label']); + unset($row['ecommerceType']); + + $columnsToRound = array( + Piwik_Archive::INDEX_ECOMMERCE_ITEM_REVENUE, + Piwik_Archive::INDEX_ECOMMERCE_ITEM_QUANTITY, + Piwik_Archive::INDEX_ECOMMERCE_ITEM_PRICE, + Piwik_Archive::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED, + ); + foreach ($columnsToRound as $column) { + if (isset($row[$column]) + && $row[$column] == round($row[$column]) + ) { + $row[$column] = round($row[$column]); + } + } + $items[$dimension][$ecommerceType][$label] = $row; + } + } + + foreach ($this->dimensions as $dimension => $recordName) { + foreach (array(Piwik_Tracker_GoalManager::IDGOAL_CART, Piwik_Tracker_GoalManager::IDGOAL_ORDER) as $ecommerceType) { + if (!isset($items[$dimension][$ecommerceType])) { + continue; + } + $recordNameInsert = $recordName; + if ($ecommerceType == Piwik_Tracker_GoalManager::IDGOAL_CART) { + $recordNameInsert = self::getItemRecordNameAbandonedCart($recordName); + } + $table = $archiveProcessing->getDataTableFromArray($items[$dimension][$ecommerceType]); + + // For "category" report, we aggregate all 5 category queries into one datatable + if ($dimension == 'idaction_category') { + foreach (array('idaction_category2', 'idaction_category3', 'idaction_category4', 'idaction_category5') as $categoryToSum) { + if (!empty($items[$categoryToSum][$ecommerceType])) { + $tableToSum = $archiveProcessing->getDataTableFromArray($items[$categoryToSum][$ecommerceType]); + $table->addDataTable($tableToSum); + } + } + } + $archiveProcessing->insertBlobRecord($recordNameInsert, $table->getSerialized()); + } + } + } + + protected function shouldArchiveEcommerceItems($archiveProcessing) + { + // Per item doesn't support segment + // Also, when querying Goal metrics for visitorType==returning, we wouldnt want to trigger an extra request + // event if it did support segment + // (if this is implented, we should have shouldProcessReportsForPlugin() support partial archiving based on which metric is requested) + if (!$archiveProcessing->getSegment()->isEmpty()) { + return false; + } + return true; + } + + static public function getItemRecordNameAbandonedCart($recordName) + { + return $recordName . '_Cart'; + } + + /** + * @param $archiveProcessing + */ + public function archivePeriod($archiveProcessing) + { + /* + * Archive Ecommerce Items + */ + if ($this->shouldArchiveEcommerceItems($archiveProcessing)) { + $dataTableToSum = $this->dimensions; + foreach ($this->dimensions as $recordName) { + $dataTableToSum[] = self::getItemRecordNameAbandonedCart($recordName); + } + $archiveProcessing->archiveDataTable($dataTableToSum); + } + + /* + * Archive General Goal metrics + */ + $goalIdsToSum = Piwik_Tracker_GoalManager::getGoalIds($archiveProcessing->idsite); + + //Ecommerce + $goalIdsToSum[] = Piwik_Tracker_GoalManager::IDGOAL_ORDER; + $goalIdsToSum[] = Piwik_Tracker_GoalManager::IDGOAL_CART; //bug here if idgoal=1 + // Overall goal metrics + $goalIdsToSum[] = false; + + $fieldsToSum = array(); + foreach ($goalIdsToSum as $goalId) { + $metricsToSum = Piwik_Goals::getGoalColumns($goalId); + unset($metricsToSum[array_search('conversion_rate', $metricsToSum)]); + foreach ($metricsToSum as $metricName) { + $fieldsToSum[] = self::getRecordName($metricName, $goalId); + } + } + $records = $archiveProcessing->archiveNumericValuesSum($fieldsToSum); + + // also recording conversion_rate for each goal + foreach ($goalIdsToSum as $goalId) { + $nb_conversions = $records[self::getRecordName('nb_visits_converted', $goalId)]; + $conversion_rate = $this->getConversionRate($nb_conversions, $archiveProcessing); + $archiveProcessing->insertNumericRecord(self::getRecordName('conversion_rate', $goalId), $conversion_rate); + + // sum up the visits to conversion data table & the days to conversion data table + $archiveProcessing->archiveDataTable(array( + self::getRecordName(self::VISITS_UNTIL_RECORD_NAME, $goalId), + self::getRecordName(self::DAYS_UNTIL_CONV_RECORD_NAME, $goalId))); + } + + // sum up goal overview reports + $archiveProcessing->archiveDataTable(array( + self::getRecordName(self::VISITS_UNTIL_RECORD_NAME), + self::getRecordName(self::DAYS_UNTIL_CONV_RECORD_NAME))); + } + +} \ No newline at end of file diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php index 15eb85c345034a5c4ca15bed0f2d795df618af5f..7f374e40f3d3240a666807d267f1fb08c5664934 100644 --- a/plugins/Goals/Controller.php +++ b/plugins/Goals/Controller.php @@ -361,7 +361,7 @@ class Piwik_Goals_Controller extends Piwik_Controller $keywordNotDefinedString = ''; if (Piwik_PluginsManager::getInstance()->isPluginActivated('Referers')) { - $keywordNotDefinedString = Piwik_Referers::getKeywordNotDefinedString(); + $keywordNotDefinedString = Piwik_Referers_API::getKeywordNotDefinedString(); $topDimensionsToLoad += array( 'keyword' => 'Referers.getKeywords', 'website' => 'Referers.getWebsites', diff --git a/plugins/Live/Visitor.php b/plugins/Live/Visitor.php index 8a8c9840214fb9e9cc92d7e4e1cc3aaa670dc19e..5228e18aa86544874f48dac27febf8a631c1e0a7 100644 --- a/plugins/Live/Visitor.php +++ b/plugins/Live/Visitor.php @@ -344,7 +344,7 @@ class Piwik_Live_Visitor if (Piwik_PluginsManager::getInstance()->isPluginActivated('Referers') && $this->getRefererType() == 'search' ) { - $keyword = Piwik_Referers::getCleanKeyword($keyword); + $keyword = Piwik_Referers_API::getCleanKeyword($keyword); } return urldecode($keyword); } @@ -353,7 +353,7 @@ class Piwik_Live_Visitor { if ($this->getRefererType() == 'search') { if (Piwik_PluginsManager::getInstance()->isPluginActivated('Referers') - && $this->details['referer_keyword'] == Piwik_Referers::LABEL_KEYWORD_NOT_DEFINED + && $this->details['referer_keyword'] == Piwik_Referers_API::LABEL_KEYWORD_NOT_DEFINED ) { return 'http://piwik.org/faq/general/#faq_144'; } // Case URL is google.XX/url.... then we rewrite to the search result page url diff --git a/plugins/Provider/Archiving.php b/plugins/Provider/Archiving.php new file mode 100644 index 0000000000000000000000000000000000000000..c0228e788fb540c5f45b84a59b613f386c000417 --- /dev/null +++ b/plugins/Provider/Archiving.php @@ -0,0 +1,30 @@ +<?php + +class Piwik_Provider_Archiving { + + + /** + * @param $archiveProcessing + */ + public function archiveDay($archiveProcessing) + { + $recordName = 'Provider_hostnameExt'; + $labelSQL = "log_visit.location_provider"; + $metricsByProvider = $archiveProcessing->getArrayInterestForLabel($labelSQL); + $tableProvider = $archiveProcessing->getDataTableFromArray($metricsByProvider); + $columnToSortByBeforeTruncation = Piwik_Archive::INDEX_NB_VISITS; + $maximumRowsInDataTable = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_standard']; + $archiveProcessing->insertBlobRecord($recordName, $tableProvider->getSerialized($maximumRowsInDataTable, null, $columnToSortByBeforeTruncation)); + } + + /** + * @param $archiveProcessing + */ + public function archivePeriod($archiveProcessing) + { + $maximumRowsInDataTable = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_standard']; + $dataTableToSum = array('Provider_hostnameExt'); + $archiveProcessing->archiveDataTable($dataTableToSum, null, $maximumRowsInDataTable); + } + +} \ No newline at end of file diff --git a/plugins/Provider/Provider.php b/plugins/Provider/Provider.php index 67a1d35371e89c1f2d470539f659e99e04d1512b..87c7de7efb36788ee0b3d34328dd4e8e3428b66f 100644 --- a/plugins/Provider/Provider.php +++ b/plugins/Provider/Provider.php @@ -114,42 +114,6 @@ class Piwik_Provider extends Piwik_Plugin Piwik_AddAction('template_footerUserCountry', array('Piwik_Provider', 'footerUserCountry')); } - /** - * @param Piwik_Event_Notification $notification notification object - * @return mixed - */ - function archivePeriod($notification) - { - $maximumRowsInDataTable = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_standard']; - $archiveProcessing = $notification->getNotificationObject(); - - if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return; - - $dataTableToSum = array('Provider_hostnameExt'); - $archiveProcessing->archiveDataTable($dataTableToSum, null, $maximumRowsInDataTable); - } - - /** - * Daily archive: processes the report Visits by Provider - * - * @param Piwik_Event_Notification $notification notification object - */ - function archiveDay($notification) - { - $archiveProcessing = $notification->getNotificationObject(); - - if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return; - - $recordName = 'Provider_hostnameExt'; - $labelSQL = "log_visit.location_provider"; - $metricsByProvider = $archiveProcessing->getArrayInterestForLabel($labelSQL); - $tableProvider = $archiveProcessing->getDataTableFromArray($metricsByProvider); - $columnToSortByBeforeTruncation = Piwik_Archive::INDEX_NB_VISITS; - $maximumRowsInDataTable = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_standard']; - $archiveProcessing->insertBlobRecord($recordName, $tableProvider->getSerialized($maximumRowsInDataTable, null, $columnToSortByBeforeTruncation)); - destroy($tableProvider); - } - /** * Logs the provider in the log_visit table * @@ -250,4 +214,38 @@ class Piwik_Provider extends Piwik_Plugin $out .= '</div>'; } + /** + * Daily archive: processes the report Visits by Provider + * + * @param Piwik_Event_Notification $notification notification object + */ + function archiveDay($notification) + { + $archiveProcessing = $notification->getNotificationObject(); + + if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) { + return; + } + + $archiving = new Piwik_Provider_Archiving(); + $archiving->archiveDay($archiveProcessing); + } + + /** + * @param Piwik_Event_Notification $notification notification object + * @return mixed + */ + function archivePeriod($notification) + { + $archiveProcessing = $notification->getNotificationObject(); + + if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) { + return; + } + + $archiving = new Piwik_Provider_Archiving(); + $archiving->archivePeriod($archiveProcessing); + } + + } diff --git a/plugins/Referers/API.php b/plugins/Referers/API.php index 6516228fd6cbc14b9de3c48e5be8fc8fb0a15247..327fa59c2cb936e54bb109f65ec256609c28a5a3 100644 --- a/plugins/Referers/API.php +++ b/plugins/Referers/API.php @@ -138,10 +138,30 @@ class Piwik_Referers_API protected function handleKeywordNotDefined($dataTable) { - $dataTable->queueFilter('ColumnCallbackReplace', array('label', array('Piwik_Referers', 'getCleanKeyword'))); + $dataTable->queueFilter('ColumnCallbackReplace', array('label', array('Piwik_Referers_API', 'getCleanKeyword'))); return $dataTable; } + const LABEL_KEYWORD_NOT_DEFINED = ""; + + /** + * @ignore + */ + static public function getKeywordNotDefinedString() + { + return Piwik_Translate('General_NotDefined', Piwik_Translate('Referers_ColumnKeyword')); + } + + /** + * @ignore + */ + static public function getCleanKeyword($label) + { + return $label == self::LABEL_KEYWORD_NOT_DEFINED + ? self::getKeywordNotDefinedString() + : $label; + } + public function getKeywordsForPageUrl($idSite, $period, $date, $url) { // Fetch the Top keywords for this page diff --git a/plugins/Referers/Archiving.php b/plugins/Referers/Archiving.php new file mode 100644 index 0000000000000000000000000000000000000000..0fca433ba3b0aa1cf19b4e78ab1f6bfb8e8a4e66 --- /dev/null +++ b/plugins/Referers/Archiving.php @@ -0,0 +1,346 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik_Plugins + * @package Piwik_Referers + */ + +class Piwik_Referers_Archiving +{ + protected $columnToSortByBeforeTruncation; + protected $maximumRowsInDataTableLevelZero; + protected $maximumRowsInSubDataTable; + + function __construct() + { + $this->columnToSortByBeforeTruncation = Piwik_Archive::INDEX_NB_VISITS; + $this->maximumRowsInDataTableLevelZero = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_referers']; + $this->maximumRowsInSubDataTable = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_referers']; + } + + /** + * @param $archiveProcessing + */ + public function archiveDay($archiveProcessing) + { + $query = $archiveProcessing->queryVisitsByDimension(array("referer_type", "referer_name", "referer_keyword", "referer_url")); + $this->aggregateFromVisits($archiveProcessing, $query); + + $query = $archiveProcessing->queryConversionsByDimension(array("referer_type", "referer_name", "referer_keyword")); + $this->aggregateFromConversions($archiveProcessing, $query); + + Piwik_PostEvent('Referers.archiveDay', $this); + $this->archiveDayRecordInDatabase($archiveProcessing); + } + + /** + * @param Piwik_ArchiveProcessing_Day $archiveProcessing + * @param $query + * @throws Exception + */ + protected function aggregateFromVisits(Piwik_ArchiveProcessing_Day $archiveProcessing, $query) + { + $this->metricsBySearchEngine = + $this->metricsByKeyword = + $this->metricsBySearchEngineAndKeyword = + $this->metricsByKeywordAndSearchEngine = + $this->metricsByWebsite = + $this->metricsByWebsiteAndUrl = + $this->metricsByCampaignAndKeyword = + $this->metricsByCampaign = + $this->metricsByType = + $this->distinctUrls = array(); + while ($row = $query->fetch()) { + $this->makeRefererTypeNonEmpty($row); + $this->aggregateVisit($archiveProcessing, $row); + $this->aggregateVisitByType($archiveProcessing, $row); + + } + } + + protected function makeRefererTypeNonEmpty(&$row) + { + if (empty($row['referer_type'])) { + $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY; + } + } + + protected function aggregateVisit(Piwik_ArchiveProcessing_Day $archiveProcessing, $row) + { + switch ($row['referer_type']) { + case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE: + $this->aggregateVisitBySearchEngine($archiveProcessing, $row); + break; + + case Piwik_Common::REFERER_TYPE_WEBSITE: + $this->aggregateVisitByWebsite($archiveProcessing, $row); + break; + + case Piwik_Common::REFERER_TYPE_CAMPAIGN: + $this->aggregateVisitByCampaign($archiveProcessing, $row); + break; + + case Piwik_Common::REFERER_TYPE_DIRECT_ENTRY: + // direct entry are aggregated below in $this->metricsByType array + break; + + default: + throw new Exception("Non expected referer_type = " . $row['referer_type']); + break; + } + } + + protected function aggregateVisitBySearchEngine(Piwik_ArchiveProcessing_Day $archiveProcessing, $row) + { + if (empty($row['referer_keyword'])) { + $row['referer_keyword'] = Piwik_Referers_API::LABEL_KEYWORD_NOT_DEFINED; + } + if (!isset($this->metricsBySearchEngine[$row['referer_name']])) { + $this->metricsBySearchEngine[$row['referer_name']] = $archiveProcessing->makeEmptyRow(); + } + if (!isset($this->metricsByKeyword[$row['referer_keyword']])) { + $this->metricsByKeyword[$row['referer_keyword']] = $archiveProcessing->makeEmptyRow(); + } + if (!isset($this->metricsBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']])) { + $this->metricsBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']] = $archiveProcessing->makeEmptyRow(); + } + if (!isset($this->metricsByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']])) { + $this->metricsByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']] = $archiveProcessing->makeEmptyRow(); + } + + $archiveProcessing->sumMetrics($row, $this->metricsBySearchEngine[$row['referer_name']]); + $archiveProcessing->sumMetrics($row, $this->metricsByKeyword[$row['referer_keyword']]); + $archiveProcessing->sumMetrics($row, $this->metricsBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]); + $archiveProcessing->sumMetrics($row, $this->metricsByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]); + } + + protected function aggregateVisitByWebsite(Piwik_ArchiveProcessing_Day $archiveProcessing, $row) + { + if (!isset($this->metricsByWebsite[$row['referer_name']])) { + $this->metricsByWebsite[$row['referer_name']] = $archiveProcessing->makeEmptyRow(); + } + $archiveProcessing->sumMetrics($row, $this->metricsByWebsite[$row['referer_name']]); + + if (!isset($this->metricsByWebsiteAndUrl[$row['referer_name']][$row['referer_url']])) { + $this->metricsByWebsiteAndUrl[$row['referer_name']][$row['referer_url']] = $archiveProcessing->makeEmptyRow(); + } + $archiveProcessing->sumMetrics($row, $this->metricsByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]); + + $urlHash = substr(md5($row['referer_url']), 0, 10); + if (!isset($this->distinctUrls[$urlHash])) { + $this->distinctUrls[$urlHash] = true; + } + } + + protected function aggregateVisitByCampaign(Piwik_ArchiveProcessing_Day $archiveProcessing, $row) + { + if (!empty($row['referer_keyword'])) { + if (!isset($this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']])) { + $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']] = $archiveProcessing->makeEmptyRow(); + } + $archiveProcessing->sumMetrics($row, $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]); + } + if (!isset($this->metricsByCampaign[$row['referer_name']])) { + $this->metricsByCampaign[$row['referer_name']] = $archiveProcessing->makeEmptyRow(); + } + $archiveProcessing->sumMetrics($row, $this->metricsByCampaign[$row['referer_name']]); + } + + protected function aggregateVisitByType(Piwik_ArchiveProcessing_Day $archiveProcessing, $row) + { + if (!isset($this->metricsByType[$row['referer_type']])) { + $this->metricsByType[$row['referer_type']] = $archiveProcessing->makeEmptyRow(); + } + $archiveProcessing->sumMetrics($row, $this->metricsByType[$row['referer_type']]); + } + + protected function aggregateFromConversions($archiveProcessing, $query) + { + if ($query === false) { + return; + } + while ($row = $query->fetch()) { + $this->makeRefererTypeNonEmpty($row); + + $skipAggregateByType = $this->aggregateConversion($archiveProcessing, $row); + if (!$skipAggregateByType) { + $this->aggregateConversionByType($archiveProcessing, $row); + } + } + + $archiveProcessing->enrichConversionsByLabelArray($this->metricsByType); + $archiveProcessing->enrichConversionsByLabelArray($this->metricsBySearchEngine); + $archiveProcessing->enrichConversionsByLabelArray($this->metricsByKeyword); + $archiveProcessing->enrichConversionsByLabelArray($this->metricsByWebsite); + $archiveProcessing->enrichConversionsByLabelArray($this->metricsByCampaign); + $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->metricsByCampaignAndKeyword); + } + + protected function aggregateConversion($archiveProcessing, $row) + { + $skipAggregateByType = false; + switch ($row['referer_type']) { + case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE: + $this->aggregateConversionBySearchEngine($archiveProcessing, $row); + break; + + case Piwik_Common::REFERER_TYPE_WEBSITE: + $this->aggregateConversionByWebsite($archiveProcessing, $row); + break; + + case Piwik_Common::REFERER_TYPE_CAMPAIGN: + $this->aggregateConversionByCampaign($archiveProcessing, $row); + break; + + case Piwik_Common::REFERER_TYPE_DIRECT_ENTRY: + // Direct entry, no sub dimension + break; + + default: + // The referer type is user submitted for goal conversions, we ignore any malformed value + // Continue to the next while iteration + $skipAggregateByType = true; + break; + } + return $skipAggregateByType; + } + + protected function aggregateConversionBySearchEngine($archiveProcessing, $row) + { + if (empty($row['referer_keyword'])) { + $row['referer_keyword'] = Piwik_Referers_API::LABEL_KEYWORD_NOT_DEFINED; + } + if (!isset($this->metricsBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) { + $this->metricsBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); + } + if (!isset($this->metricsByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) { + $this->metricsByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); + } + + $archiveProcessing->sumGoalMetrics($row, $this->metricsBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + $archiveProcessing->sumGoalMetrics($row, $this->metricsByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + } + + protected function aggregateConversionByWebsite($archiveProcessing, $row) + { + if (!isset($this->metricsByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) { + $this->metricsByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); + } + $archiveProcessing->sumGoalMetrics($row, $this->metricsByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + } + + protected function aggregateConversionByCampaign($archiveProcessing, $row) + { + if (!empty($row['referer_keyword'])) { + if (!isset($this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) { + $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); + } + $archiveProcessing->sumGoalMetrics($row, $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + } + if (!isset($this->metricsByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) { + $this->metricsByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); + } + $archiveProcessing->sumGoalMetrics($row, $this->metricsByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + } + + protected function aggregateConversionByType($archiveProcessing, $row) + { + if (!isset($this->metricsByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) { + $this->metricsByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); + } + $archiveProcessing->sumGoalMetrics($row, $this->metricsByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); + } + + /** + * Records the daily stats (numeric or datatable blob) into the archive tables. + * + * @param Piwik_ArchiveProcessing $archiveProcessing + * @return void + */ + protected function archiveDayRecordInDatabase($archiveProcessing) + { + $numericRecords = array( + 'Referers_distinctSearchEngines' => count($this->metricsBySearchEngineAndKeyword), + 'Referers_distinctKeywords' => count($this->metricsByKeywordAndSearchEngine), + 'Referers_distinctCampaigns' => count($this->metricsByCampaign), + 'Referers_distinctWebsites' => count($this->metricsByWebsite), + 'Referers_distinctWebsitesUrls' => count($this->distinctUrls), + ); + + foreach ($numericRecords as $name => $value) { + $archiveProcessing->insertNumericRecord($name, $value); + } + + $dataTable = $archiveProcessing->getDataTableSerialized($this->metricsByType); + $archiveProcessing->insertBlobRecord('Referers_type', $dataTable); + destroy($dataTable); + + $blobRecords = array( + 'Referers_keywordBySearchEngine' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsBySearchEngineAndKeyword, $this->metricsBySearchEngine), + 'Referers_searchEngineByKeyword' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByKeywordAndSearchEngine, $this->metricsByKeyword), + 'Referers_keywordByCampaign' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByCampaignAndKeyword, $this->metricsByCampaign), + 'Referers_urlByWebsite' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByWebsiteAndUrl, $this->metricsByWebsite), + ); + foreach ($blobRecords as $recordName => $table) { + $blob = $table->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation); + $archiveProcessing->insertBlobRecord($recordName, $blob); + destroy($table); + } + } + + /** + * @param $archiveProcessing + */ + public function archivePeriod($archiveProcessing) + { + $dataTableToSum = array( + 'Referers_type', + 'Referers_keywordBySearchEngine', + 'Referers_searchEngineByKeyword', + 'Referers_keywordByCampaign', + 'Referers_urlByWebsite', + ); + $nameToCount = $archiveProcessing->archiveDataTable($dataTableToSum, null, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation); + + $mappingFromArchiveName = array( + 'Referers_distinctSearchEngines' => + array('typeCountToUse' => 'level0', + 'nameTableToUse' => 'Referers_keywordBySearchEngine', + ), + 'Referers_distinctKeywords' => + array('typeCountToUse' => 'level0', + 'nameTableToUse' => 'Referers_searchEngineByKeyword', + ), + 'Referers_distinctCampaigns' => + array('typeCountToUse' => 'level0', + 'nameTableToUse' => 'Referers_keywordByCampaign', + ), + 'Referers_distinctWebsites' => + array('typeCountToUse' => 'level0', + 'nameTableToUse' => 'Referers_urlByWebsite', + ), + 'Referers_distinctWebsitesUrls' => + array('typeCountToUse' => 'recursive', + 'nameTableToUse' => 'Referers_urlByWebsite', + ), + ); + + foreach ($mappingFromArchiveName as $name => $infoMapping) { + $typeCountToUse = $infoMapping['typeCountToUse']; + $nameTableToUse = $infoMapping['nameTableToUse']; + + if ($typeCountToUse == 'recursive') { + + $countValue = $nameToCount[$nameTableToUse]['recursive'] + - $nameToCount[$nameTableToUse]['level0']; + } else { + $countValue = $nameToCount[$nameTableToUse]['level0']; + } + $archiveProcessing->insertNumericRecord($name, $countValue); + } + } +} \ No newline at end of file diff --git a/plugins/Referers/Referers.php b/plugins/Referers/Referers.php index 2c36a17d5a7f797054646f780b6dca238050869f..814e78f19b3f73c384ea4df5c2aea371053a60a1 100644 --- a/plugins/Referers/Referers.php +++ b/plugins/Referers/Referers.php @@ -19,21 +19,14 @@ require_once PIWIK_INCLUDE_PATH . '/plugins/Referers/functions.php'; */ class Piwik_Referers extends Piwik_Plugin { - public $archiveProcessing; - protected $columnToSortByBeforeTruncation; - protected $maximumRowsInDataTableLevelZero; - protected $maximumRowsInSubDataTable; - public function getInformation() { - $info = array( + return array( 'description' => Piwik_Translate('Referers_PluginDescription'), 'author' => 'Piwik', 'author_homepage' => 'http://piwik.org/', 'version' => Piwik_Version::VERSION, ); - - return $info; } function getListHooksRegistered() @@ -289,86 +282,6 @@ class Piwik_Referers extends Piwik_Plugin )); } - function __construct() - { - $this->columnToSortByBeforeTruncation = Piwik_Archive::INDEX_NB_VISITS; - $this->maximumRowsInDataTableLevelZero = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_referers']; - $this->maximumRowsInSubDataTable = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_referers']; - } - - /** - * Period archiving: sums up daily stats and sums report tables, - * making sure that tables are still truncated. - * - * @param Piwik_Event_Notification $notification notification object - * @return void - */ - function archivePeriod($notification) - { - $archiveProcessing = $notification->getNotificationObject(); - - if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return; - - $dataTableToSum = array( - 'Referers_type', - 'Referers_keywordBySearchEngine', - 'Referers_searchEngineByKeyword', - 'Referers_keywordByCampaign', - 'Referers_urlByWebsite', - ); - $nameToCount = $archiveProcessing->archiveDataTable($dataTableToSum, null, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation); - - $mappingFromArchiveName = array( - 'Referers_distinctSearchEngines' => - array('typeCountToUse' => 'level0', - 'nameTableToUse' => 'Referers_keywordBySearchEngine', - ), - 'Referers_distinctKeywords' => - array('typeCountToUse' => 'level0', - 'nameTableToUse' => 'Referers_searchEngineByKeyword', - ), - 'Referers_distinctCampaigns' => - array('typeCountToUse' => 'level0', - 'nameTableToUse' => 'Referers_keywordByCampaign', - ), - 'Referers_distinctWebsites' => - array('typeCountToUse' => 'level0', - 'nameTableToUse' => 'Referers_urlByWebsite', - ), - 'Referers_distinctWebsitesUrls' => - array('typeCountToUse' => 'recursive', - 'nameTableToUse' => 'Referers_urlByWebsite', - ), - ); - - foreach ($mappingFromArchiveName as $name => $infoMapping) { - $typeCountToUse = $infoMapping['typeCountToUse']; - $nameTableToUse = $infoMapping['nameTableToUse']; - - if ($typeCountToUse == 'recursive') { - - $countValue = $nameToCount[$nameTableToUse]['recursive'] - - $nameToCount[$nameTableToUse]['level0']; - } else { - $countValue = $nameToCount[$nameTableToUse]['level0']; - } - $archiveProcessing->insertNumericRecord($name, $countValue); - } - } - - const LABEL_KEYWORD_NOT_DEFINED = ""; - - static public function getKeywordNotDefinedString() - { - return Piwik_Translate('General_NotDefined', Piwik_Translate('Referers_ColumnKeyword')); - } - - static public function getCleanKeyword($label) - { - return $label == Piwik_Referers::LABEL_KEYWORD_NOT_DEFINED - ? self::getKeywordNotDefinedString() - : $label; - } /** * Hooks on daily archive to trigger various log processing @@ -381,208 +294,33 @@ class Piwik_Referers extends Piwik_Plugin /** * @var Piwik_ArchiveProcessing_Day */ - $this->archiveProcessing = $notification->getNotificationObject(); - if (!$this->archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return; - - $this->archiveDayAggregateVisits($this->archiveProcessing); - $this->archiveDayAggregateGoals($this->archiveProcessing); - Piwik_PostEvent('Referers.archiveDay', $this); - $this->archiveDayRecordInDatabase($this->archiveProcessing); - $this->cleanup(); - } - - protected function cleanup() - { - destroy($this->metricsBySearchEngine); - destroy($this->metricsByKeyword); - destroy($this->metricsBySearchEngineAndKeyword); - destroy($this->metricsByKeywordAndSearchEngine); - destroy($this->metricsByWebsite); - destroy($this->metricsByWebsiteAndUrl); - destroy($this->metricsByCampaignAndKeyword); - destroy($this->metricsByCampaign); - destroy($this->metricsByType); - destroy($this->distinctUrls); - } - - /** - * Daily archive: processes all Referers reports, eg. Visits by Keyword, - * Visits by websites, etc. - * - * @param Piwik_ArchiveProcessing $archiveProcessing - * @throws Exception - * @return void - */ - protected function archiveDayAggregateVisits(Piwik_ArchiveProcessing_Day $archiveProcessing) - { - $dimension = array("referer_type", "referer_name", "referer_keyword", "referer_url"); - $query = $archiveProcessing->queryVisitsByDimension($dimension); - - $this->metricsBySearchEngine = - $this->metricsByKeyword = - $this->metricsBySearchEngineAndKeyword = - $this->metricsByKeywordAndSearchEngine = - $this->metricsByWebsite = - $this->metricsByWebsiteAndUrl = - $this->metricsByCampaignAndKeyword = - $this->metricsByCampaign = - $this->metricsByType = - $this->distinctUrls = array(); - while ($row = $query->fetch()) { - if (empty($row['referer_type'])) { - $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY; - } else { - switch ($row['referer_type']) { - case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE: - if (empty($row['referer_keyword'])) { - $row['referer_keyword'] = self::LABEL_KEYWORD_NOT_DEFINED; - } - if (!isset($this->metricsBySearchEngine[$row['referer_name']])) $this->metricsBySearchEngine[$row['referer_name']] = $archiveProcessing->makeEmptyRow(); - if (!isset($this->metricsByKeyword[$row['referer_keyword']])) $this->metricsByKeyword[$row['referer_keyword']] = $archiveProcessing->makeEmptyRow(); - if (!isset($this->metricsBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->metricsBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']] = $archiveProcessing->makeEmptyRow(); - if (!isset($this->metricsByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']])) $this->metricsByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']] = $archiveProcessing->makeEmptyRow(); - - $archiveProcessing->sumMetrics($row, $this->metricsBySearchEngine[$row['referer_name']]); - $archiveProcessing->sumMetrics($row, $this->metricsByKeyword[$row['referer_keyword']]); - $archiveProcessing->sumMetrics($row, $this->metricsBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]); - $archiveProcessing->sumMetrics($row, $this->metricsByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]); - break; - - case Piwik_Common::REFERER_TYPE_WEBSITE: - - if (!isset($this->metricsByWebsite[$row['referer_name']])) $this->metricsByWebsite[$row['referer_name']] = $archiveProcessing->makeEmptyRow(); - $archiveProcessing->sumMetrics($row, $this->metricsByWebsite[$row['referer_name']]); - - if (!isset($this->metricsByWebsiteAndUrl[$row['referer_name']][$row['referer_url']])) $this->metricsByWebsiteAndUrl[$row['referer_name']][$row['referer_url']] = $archiveProcessing->makeEmptyRow(); - $archiveProcessing->sumMetrics($row, $this->metricsByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]); - - if (!isset($this->distinctUrls[$row['referer_url']])) { - $this->distinctUrls[$row['referer_url']] = true; - } - break; - - case Piwik_Common::REFERER_TYPE_CAMPAIGN: - if (!empty($row['referer_keyword'])) { - if (!isset($this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']] = $archiveProcessing->makeEmptyRow(); - $archiveProcessing->sumMetrics($row, $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]); - } - if (!isset($this->metricsByCampaign[$row['referer_name']])) $this->metricsByCampaign[$row['referer_name']] = $archiveProcessing->makeEmptyRow(); - $archiveProcessing->sumMetrics($row, $this->metricsByCampaign[$row['referer_name']]); - break; - - case Piwik_Common::REFERER_TYPE_DIRECT_ENTRY: - // direct entry are aggregated below in $this->metricsByType array - break; - - default: - throw new Exception("Non expected referer_type = " . $row['referer_type']); - break; - } - } - if (!isset($this->metricsByType[$row['referer_type']])) $this->metricsByType[$row['referer_type']] = $archiveProcessing->makeEmptyRow(); - $archiveProcessing->sumMetrics($row, $this->metricsByType[$row['referer_type']]); + $archiveProcessing = $notification->getNotificationObject(); + if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) { + return; } - } - - /** - * Daily Goal archiving: processes reports of Goal conversions by Keyword, - * Goal conversions by Referer Websites, etc. - * - * @param Piwik_ArchiveProcessing $archiveProcessing - * @return void - */ - protected function archiveDayAggregateGoals($archiveProcessing) - { - $query = $archiveProcessing->queryConversionsByDimension(array("referer_type", "referer_name", "referer_keyword")); - - if ($query === false) return; - while ($row = $query->fetch()) { - if (empty($row['referer_type'])) { - $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY; - } else { - switch ($row['referer_type']) { - case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE: - if (empty($row['referer_keyword'])) { - $row['referer_keyword'] = self::LABEL_KEYWORD_NOT_DEFINED; - } - if (!isset($this->metricsBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->metricsBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); - if (!isset($this->metricsByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->metricsByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); - - $archiveProcessing->sumGoalMetrics($row, $this->metricsBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); - $archiveProcessing->sumGoalMetrics($row, $this->metricsByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); - break; - case Piwik_Common::REFERER_TYPE_WEBSITE: - if (!isset($this->metricsByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->metricsByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); - $archiveProcessing->sumGoalMetrics($row, $this->metricsByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); - break; - - case Piwik_Common::REFERER_TYPE_CAMPAIGN: - if (!empty($row['referer_keyword'])) { - if (!isset($this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); - $archiveProcessing->sumGoalMetrics($row, $this->metricsByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); - } - if (!isset($this->metricsByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->metricsByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); - $archiveProcessing->sumGoalMetrics($row, $this->metricsByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); - break; + $archiving = new Piwik_Referers_Archiving(); + $archiving->archiveDay($archiveProcessing); + } - case Piwik_Common::REFERER_TYPE_DIRECT_ENTRY: - // Direct entry, no sub dimension - break; - default: - // The referer type is user submitted for goal conversions, we ignore any malformed value - // Continue to the next while iteration - continue 2; - break; - } - } - if (!isset($this->metricsByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->metricsByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->makeEmptyGoalRow($row['idgoal']); - $archiveProcessing->sumGoalMetrics($row, $this->metricsByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]); - } - - $archiveProcessing->enrichConversionsByLabelArray($this->metricsByType); - $archiveProcessing->enrichConversionsByLabelArray($this->metricsBySearchEngine); - $archiveProcessing->enrichConversionsByLabelArray($this->metricsByKeyword); - $archiveProcessing->enrichConversionsByLabelArray($this->metricsByWebsite); - $archiveProcessing->enrichConversionsByLabelArray($this->metricsByCampaign); - $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->metricsByCampaignAndKeyword); - } /** - * Records the daily stats (numeric or datatable blob) into the archive tables. + * Period archiving: sums up daily stats and sums report tables, + * making sure that tables are still truncated. * - * @param Piwik_ArchiveProcessing $archiveProcessing + * @param Piwik_Event_Notification $notification notification object * @return void */ - protected function archiveDayRecordInDatabase($archiveProcessing) + function archivePeriod($notification) { - $numericRecords = array( - 'Referers_distinctSearchEngines' => count($this->metricsBySearchEngineAndKeyword), - 'Referers_distinctKeywords' => count($this->metricsByKeywordAndSearchEngine), - 'Referers_distinctCampaigns' => count($this->metricsByCampaign), - 'Referers_distinctWebsites' => count($this->metricsByWebsite), - 'Referers_distinctWebsitesUrls' => count($this->distinctUrls), - ); + $archiveProcessing = $notification->getNotificationObject(); - foreach ($numericRecords as $name => $value) { - $archiveProcessing->insertNumericRecord($name, $value); + if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) { + return; } - $dataTable = $archiveProcessing->getDataTableSerialized($this->metricsByType); - $archiveProcessing->insertBlobRecord('Referers_type', $dataTable); - destroy($dataTable); - - $blobRecords = array( - 'Referers_keywordBySearchEngine' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsBySearchEngineAndKeyword, $this->metricsBySearchEngine), - 'Referers_searchEngineByKeyword' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByKeywordAndSearchEngine, $this->metricsByKeyword), - 'Referers_keywordByCampaign' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByCampaignAndKeyword, $this->metricsByCampaign), - 'Referers_urlByWebsite' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->metricsByWebsiteAndUrl, $this->metricsByWebsite), - ); - foreach ($blobRecords as $recordName => $table) { - $blob = $table->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation); - $archiveProcessing->insertBlobRecord($recordName, $blob); - destroy($table); - } + $archiving = new Piwik_Referers_Archiving(); + $archiving->archivePeriod($archiveProcessing); } } diff --git a/plugins/Referers/functions.php b/plugins/Referers/functions.php index c7d69386c7fa0a096d85fb5faf514369d1c260a6..46d9e180007fa5fbcb3f421121e728b9a18679e0 100644 --- a/plugins/Referers/functions.php +++ b/plugins/Referers/functions.php @@ -178,7 +178,7 @@ function Piwik_getSearchEngineHostPathFromUrl($url) */ function Piwik_getSearchEngineUrlFromUrlAndKeyword($url, $keyword) { - if ($keyword === Piwik_Referers::LABEL_KEYWORD_NOT_DEFINED) { + if ($keyword === Piwik_Referers_API::LABEL_KEYWORD_NOT_DEFINED) { return 'http://piwik.org/faq/general/#faq_144'; } $searchEngineUrls = Piwik_Common::getSearchEngineUrls(); diff --git a/plugins/Transitions/Transitions.php b/plugins/Transitions/Transitions.php index 4adaf3f9974e684527b93c2ea45708965a79a0fa..765854bff7c50201e675c11276c1b4ffcc73713f 100644 --- a/plugins/Transitions/Transitions.php +++ b/plugins/Transitions/Transitions.php @@ -118,7 +118,7 @@ class Piwik_Transitions extends Piwik_Plugin foreach ($subData as &$row) { if ($referrerType == Piwik_Common::REFERER_TYPE_SEARCH_ENGINE && empty($row['referrer_data'])) { - $row['referrer_data'] = Piwik_Referers::LABEL_KEYWORD_NOT_DEFINED; + $row['referrer_data'] = Piwik_Referers_API::LABEL_KEYWORD_NOT_DEFINED; } $referrerData[$referrerType][Piwik_Archive::INDEX_NB_VISITS] += $row[Piwik_Archive::INDEX_NB_VISITS]; diff --git a/plugins/UserCountry/API.php b/plugins/UserCountry/API.php index d8cdb266b6736c54e78aa5c19515de9d52b9f4e1..36dfffe4186edf50284887090110f22517147d8b 100644 --- a/plugins/UserCountry/API.php +++ b/plugins/UserCountry/API.php @@ -32,7 +32,7 @@ class Piwik_UserCountry_API public function getCountry($idSite, $period, $date, $segment = false) { - $recordName = Piwik_UserCountry::VISITS_BY_COUNTRY_RECORD_NAME; + $recordName = Piwik_UserCountry_Archiving::VISITS_BY_COUNTRY_RECORD_NAME; $dataTable = $this->getDataTable($recordName, $idSite, $period, $date, $segment); // apply filter on the whole datatable in order the inline search to work (searches @@ -48,7 +48,7 @@ class Piwik_UserCountry_API public function getContinent($idSite, $period, $date, $segment = false) { - $recordName = Piwik_UserCountry::VISITS_BY_COUNTRY_RECORD_NAME; + $recordName = Piwik_UserCountry_Archiving::VISITS_BY_COUNTRY_RECORD_NAME; $dataTable = $this->getDataTable($recordName, $idSite, $period, $date, $segment); $getContinent = array('Piwik_Common', 'getContinent'); @@ -71,10 +71,10 @@ class Piwik_UserCountry_API */ public function getRegion($idSite, $period, $date, $segment = false) { - $recordName = Piwik_UserCountry::VISITS_BY_REGION_RECORD_NAME; + $recordName = Piwik_UserCountry_Archiving::VISITS_BY_REGION_RECORD_NAME; $dataTable = $this->getDataTable($recordName, $idSite, $period, $date, $segment); - $separator = Piwik_UserCountry::LOCATION_SEPARATOR; + $separator = Piwik_UserCountry_Archiving::LOCATION_SEPARATOR; $unk = Piwik_Tracker_Visit::UNKNOWN_CODE; // split the label and put the elements into the 'region' and 'country' metadata fields @@ -114,10 +114,10 @@ class Piwik_UserCountry_API */ public function getCity($idSite, $period, $date, $segment = false) { - $recordName = Piwik_UserCountry::VISITS_BY_CITY_RECORD_NAME; + $recordName = Piwik_UserCountry_Archiving::VISITS_BY_CITY_RECORD_NAME; $dataTable = $this->getDataTable($recordName, $idSite, $period, $date, $segment); - $separator = Piwik_UserCountry::LOCATION_SEPARATOR; + $separator = Piwik_UserCountry_Archiving::LOCATION_SEPARATOR; $unk = Piwik_Tracker_Visit::UNKNOWN_CODE; // split the label and put the elements into the 'city_name', 'region', 'country', diff --git a/plugins/UserCountry/Archiving.php b/plugins/UserCountry/Archiving.php new file mode 100644 index 0000000000000000000000000000000000000000..4c049ff6b9664a7fca381d6fc6a3afe7cbc4026d --- /dev/null +++ b/plugins/UserCountry/Archiving.php @@ -0,0 +1,210 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik_Plugins + * @package Piwik_UserCountry + */ + +class Piwik_UserCountry_Archiving +{ + const VISITS_BY_COUNTRY_RECORD_NAME = 'UserCountry_country'; + const VISITS_BY_REGION_RECORD_NAME = 'UserCountry_region'; + const VISITS_BY_CITY_RECORD_NAME = 'UserCountry_city'; + const DISTINCT_COUNTRIES_METRIC = 'UserCountry_distinctCountries'; + + // separate region, city & country info in stored report labels + const LOCATION_SEPARATOR = '|'; + + private $latLongForCities = array(); + + public function archiveDay($archiveProcessing) + { + $this->metricsByDimension = array('location_country' => array(), + 'location_region' => array(), + 'location_city' => array()); + $this->aggregateFromVisits($archiveProcessing); + $this->aggregateFromConversions($archiveProcessing); + $this->archiveDayRecordInDatabase($archiveProcessing); + } + + /** + * @param Piwik_ArchiveProcessing_Day $archiveProcessing + */ + protected function aggregateFromVisits($archiveProcessing) + { + $dimensions = array_keys($this->metricsByDimension); + $query = $archiveProcessing->queryVisitsByDimension( + $dimensions, + $where = '', + $metrics = false, + $orderBy = false, + $rankingQuery = null, + $addSelect = 'MAX(log_visit.location_latitude) as location_latitude, + MAX(log_visit.location_longitude) as location_longitude' + ); + + if ($query === false) { + return; + } + + while ($row = $query->fetch()) { + $this->makeRegionCityLabelsUnique($row); + $this->rememberCityLatLong($row); + $this->aggregateConversion($archiveProcessing, $row); + } + } + + /** + * Makes sure the region and city of a query row are unique. + * + * @param array $row + */ + private function makeRegionCityLabelsUnique(&$row) + { + static $locationColumns = array('location_region', 'location_country', 'location_city'); + + // to be on the safe side, remove the location separator from the region/city/country we + // get from the query + foreach ($locationColumns as $column) { + $row[$column] = str_replace(self::LOCATION_SEPARATOR, '', $row[$column]); + } + + if (!empty($row['location_region'])) // do not differentiate between unknown regions + { + $row['location_region'] = $row['location_region'] . self::LOCATION_SEPARATOR . $row['location_country']; + } + + if (!empty($row['location_city'])) // do not differentiate between unknown cities + { + $row['location_city'] = $row['location_city'] . self::LOCATION_SEPARATOR . $row['location_region']; + } + } + + protected function rememberCityLatLong($row) + { + $lat = $long = false; + if (!empty($row['location_city'])) { + if (!empty($row['location_latitude'])) { + $lat = $row['location_latitude']; + } + if (!empty($row['location_longitude'])) { + $long = $row['location_longitude']; + } + } + + // store latitude/longitude, if we should + if ($lat !== false && $long !== false + && empty($this->latLongForCities[$row['location_city']]) + ) { + $this->latLongForCities[$row['location_city']] = array($lat, $long); + } + } + + protected function aggregateConversion($archiveProcessing, $row) + { + foreach ($this->metricsByDimension as $dimension => &$table) { + $label = (string)$row[$dimension]; + + if (!isset($table[$label])) { + $table[$label] = $archiveProcessing->makeEmptyRow(); + } + $archiveProcessing->sumMetrics($row, $table[$label]); + } + return $table; + } + + /** + * @param Piwik_ArchiveProcessing_Day $archiveProcessing + */ + protected function aggregateFromConversions($archiveProcessing) + { + $dimensions = array_keys($this->metricsByDimension); + $query = $archiveProcessing->queryConversionsByDimension($dimensions); + + if ($query === false) { + return; + } + + while ($row = $query->fetch()) { + $this->makeRegionCityLabelsUnique($row); + + $idGoal = $row['idgoal']; + foreach ($this->metricsByDimension as $dimension => &$table) { + $label = (string)$row[$dimension]; + + if (!isset($table[$label][Piwik_Archive::INDEX_GOALS][$idGoal])) { + $table[$label][Piwik_Archive::INDEX_GOALS][$idGoal] = $archiveProcessing->makeEmptyGoalRow($idGoal); + } + + $archiveProcessing->sumGoalMetrics($row, $table[$label][Piwik_Archive::INDEX_GOALS][$idGoal]); + } + } + + foreach ($this->metricsByDimension as &$table) { + $archiveProcessing->enrichConversionsByLabelArray($table); + } + } + + /** + * @param Piwik_ArchiveProcessing_Day $archiveProcessing + */ + protected function archiveDayRecordInDatabase($archiveProcessing) + { + $maximumRows = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_standard']; + + $tableCountry = Piwik_ArchiveProcessing_Day::getDataTableFromArray($this->metricsByDimension['location_country']); + $archiveProcessing->insertBlobRecord(self::VISITS_BY_COUNTRY_RECORD_NAME, $tableCountry->getSerialized()); + $archiveProcessing->insertNumericRecord(self::DISTINCT_COUNTRIES_METRIC, $tableCountry->getRowsCount()); + destroy($tableCountry); + + $tableRegion = Piwik_ArchiveProcessing_Day::getDataTableFromArray($this->metricsByDimension['location_region']); + $serialized = $tableRegion->getSerialized($maximumRows, $maximumRows, Piwik_Archive::INDEX_NB_VISITS); + $archiveProcessing->insertBlobRecord(self::VISITS_BY_REGION_RECORD_NAME, $serialized); + destroy($tableRegion); + + $tableCity = Piwik_ArchiveProcessing_Day::getDataTableFromArray($this->metricsByDimension['location_city']); + $this->setLatitudeLongitude($tableCity); + $serialized = $tableCity->getSerialized($maximumRows, $maximumRows, Piwik_Archive::INDEX_NB_VISITS); + $archiveProcessing->insertBlobRecord(self::VISITS_BY_CITY_RECORD_NAME, $serialized); + destroy($tableCity); + } + + /** + * Utility method, appends latitude/longitude pairs to city table labels, if that data + * exists for the city. + */ + private function setLatitudeLongitude($tableCity) + { + foreach ($tableCity->getRows() as $row) { + $label = $row->getColumn('label'); + if (isset($this->latLongForCities[$label])) { + // get lat/long for city + list($lat, $long) = $this->latLongForCities[$label]; + $lat = round($lat, Piwik_UserCountry_LocationProvider::GEOGRAPHIC_COORD_PRECISION); + $long = round($long, Piwik_UserCountry_LocationProvider::GEOGRAPHIC_COORD_PRECISION); + + // set latitude + longitude metadata + $row->setMetadata('lat', $lat); + $row->setMetadata('long', $long); + } + } + } + + public function archivePeriod($archiveProcessing) + { + $dataTableToSum = array( + self::VISITS_BY_COUNTRY_RECORD_NAME, + self::VISITS_BY_REGION_RECORD_NAME, + self::VISITS_BY_CITY_RECORD_NAME, + ); + + $nameToCount = $archiveProcessing->archiveDataTable($dataTableToSum); + $archiveProcessing->insertNumericRecord(self::DISTINCT_COUNTRIES_METRIC, + $nameToCount[self::VISITS_BY_COUNTRY_RECORD_NAME]['level0']); + } + +} \ No newline at end of file diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php index 03df8bc3f7ff27006c847ffce76d7692aff8013c..fb928ba67b237b24ec20e377ef83ef1cd987aaee 100644 --- a/plugins/UserCountry/UserCountry.php +++ b/plugins/UserCountry/UserCountry.php @@ -20,14 +20,6 @@ require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/GeoIPAutoUpdater.php'; */ class Piwik_UserCountry extends Piwik_Plugin { - const VISITS_BY_COUNTRY_RECORD_NAME = 'UserCountry_country'; - const VISITS_BY_REGION_RECORD_NAME = 'UserCountry_region'; - const VISITS_BY_CITY_RECORD_NAME = 'UserCountry_city'; - - const DISTINCT_COUNTRIES_METRIC = 'UserCountry_distinctCountries'; - - // separate region, city & country info in stored report labels - const LOCATION_SEPARATOR = '|'; public function getInformation() { @@ -299,187 +291,30 @@ class Piwik_UserCountry extends Piwik_Plugin */ function archivePeriod($notification) { - /** - * @param Piwik_ArchiveProcessing_Period $archiveProcessing - */ $archiveProcessing = $notification->getNotificationObject(); + if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) { + return; + } - if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return; - - $dataTableToSum = array( - self::VISITS_BY_COUNTRY_RECORD_NAME, - self::VISITS_BY_REGION_RECORD_NAME, - self::VISITS_BY_CITY_RECORD_NAME, - ); - - $nameToCount = $archiveProcessing->archiveDataTable($dataTableToSum); - $archiveProcessing->insertNumericRecord(self::DISTINCT_COUNTRIES_METRIC, - $nameToCount[self::VISITS_BY_COUNTRY_RECORD_NAME]['level0']); + $archiving = new Piwik_UserCountry_Archiving(); + $archiving->archivePeriod($archiveProcessing); } - private $interestTables = null; - private $latLongForCities = null; - /** * @param Piwik_Event_Notification $notification notification object * @return mixed */ function archiveDay($notification) { - /** - * @var Piwik_ArchiveProcessing - */ $archiveProcessing = $notification->getNotificationObject(); - - if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return; - - $this->interestTables = array('location_country' => array(), - 'location_region' => array(), - 'location_city' => array()); - $this->latLongForCities = array(); - - $this->archiveDayAggregateVisits($archiveProcessing); - $this->archiveDayAggregateGoals($archiveProcessing); - $this->archiveDayRecordInDatabase($archiveProcessing); - - unset($this->interestTables); - unset($this->latLongForCities); - } - - /** - * @param Piwik_ArchiveProcessing_Day $archiveProcessing - */ - protected function archiveDayAggregateVisits($archiveProcessing) - { - $dimensions = array_keys($this->interestTables); - $query = $archiveProcessing->queryVisitsByDimension( - $dimensions, - $where = '', - $metrics = false, - $orderBy = false, - $rankingQuery = null, - $addSelect = 'MAX(log_visit.location_latitude) as location_latitude, - MAX(log_visit.location_longitude) as location_longitude' - ); - - if ($query === false) { + if (!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) { return; } - while ($row = $query->fetch()) { - // get latitude/longitude if there's a city - $lat = $long = false; - if (!empty($row['location_city'])) { - if (!empty($row['location_latitude'])) { - $lat = $row['location_latitude']; - } - if (!empty($row['location_longitude'])) { - $long = $row['location_longitude']; - } - } - - // make sure regions & cities w/ the same name don't get merged - $this->setLongCityRegionId($row); - - // store latitude/longitude, if we should - if ($lat !== false && $long !== false) { - $this->latLongForCities[$row['location_city']] = array($lat, $long); - } - - // add the stats to each dimension's table - foreach ($this->interestTables as $dimension => &$table) { - $label = (string)$row[$dimension]; - - if (!isset($table[$label])) { - $table[$label] = $archiveProcessing->makeEmptyRow(); - } - $archiveProcessing->sumMetrics($row, $table[$label]); - } - } + $archiving = new Piwik_UserCountry_Archiving(); + $archiving->archiveDay($archiveProcessing); } - /** - * @param Piwik_ArchiveProcessing_Day $archiveProcessing - */ - protected function archiveDayAggregateGoals($archiveProcessing) - { - $dimensions = array_keys($this->interestTables); - $query = $archiveProcessing->queryConversionsByDimension($dimensions); - - if ($query === false) { - return; - } - - while ($row = $query->fetch()) { - // make sure regions & cities w/ the same name don't get merged - $this->setLongCityRegionId($row); - - $idGoal = $row['idgoal']; - foreach ($this->interestTables as $dimension => &$table) { - $label = (string)$row[$dimension]; - - if (!isset($table[$label][Piwik_Archive::INDEX_GOALS][$idGoal])) { - $table[$label][Piwik_Archive::INDEX_GOALS][$idGoal] = $archiveProcessing->makeEmptyGoalRow($idGoal); - } - - $archiveProcessing->sumGoalMetrics($row, $table[$label][Piwik_Archive::INDEX_GOALS][$idGoal]); - } - } - - foreach ($this->interestTables as &$table) { - $archiveProcessing->enrichConversionsByLabelArray($table); - } - } - - /** - * @param Piwik_ArchiveProcessing_Day $archiveProcessing - */ - protected function archiveDayRecordInDatabase($archiveProcessing) - { - $maximumRows = Piwik_Config::getInstance()->General['datatable_archiving_maximum_rows_standard']; - - $tableCountry = Piwik_ArchiveProcessing_Day::getDataTableFromArray($this->interestTables['location_country']); - $archiveProcessing->insertBlobRecord(self::VISITS_BY_COUNTRY_RECORD_NAME, $tableCountry->getSerialized()); - $archiveProcessing->insertNumericRecord(self::DISTINCT_COUNTRIES_METRIC, $tableCountry->getRowsCount()); - destroy($tableCountry); - - $tableRegion = Piwik_ArchiveProcessing_Day::getDataTableFromArray($this->interestTables['location_region']); - $serialized = $tableRegion->getSerialized($maximumRows, $maximumRows, Piwik_Archive::INDEX_NB_VISITS); - $archiveProcessing->insertBlobRecord(self::VISITS_BY_REGION_RECORD_NAME, $serialized); - destroy($tableRegion); - - $tableCity = Piwik_ArchiveProcessing_Day::getDataTableFromArray($this->interestTables['location_city']); - $this->setLatitudeLongitude($tableCity); - $serialized = $tableCity->getSerialized($maximumRows, $maximumRows, Piwik_Archive::INDEX_NB_VISITS); - $archiveProcessing->insertBlobRecord(self::VISITS_BY_CITY_RECORD_NAME, $serialized); - destroy($tableCity); - } - - /** - * Makes sure the region and city of a query row are unique. - * - * @param array $row - */ - private function setLongCityRegionId(&$row) - { - static $locationColumns = array('location_region', 'location_country', 'location_city'); - - // to be on the safe side, remove the location separator from the region/city/country we - // get from the query - foreach ($locationColumns as $column) { - $row[$column] = str_replace(self::LOCATION_SEPARATOR, '', $row[$column]); - } - - if (!empty($row['location_region'])) // do not differentiate between unknown regions - { - $row['location_region'] = $row['location_region'] . self::LOCATION_SEPARATOR . $row['location_country']; - } - - if (!empty($row['location_city'])) // do not differentiate between unknown cities - { - $row['location_city'] = $row['location_city'] . self::LOCATION_SEPARATOR . $row['location_region']; - } - } /** * Returns a list of country codes for a given continent code. @@ -500,24 +335,4 @@ class Piwik_UserCountry extends Piwik_Plugin 'bind' => '-'); // HACK: SegmentExpression requires a $bind, even if there's nothing to bind } - /** - * Utility method, appends latitude/longitude pairs to city table labels, if that data - * exists for the city. - */ - private function setLatitudeLongitude($tableCity) - { - foreach ($tableCity->getRows() as $row) { - $label = $row->getColumn('label'); - if (isset($this->latLongForCities[$label])) { - // get lat/long for city - list($lat, $long) = $this->latLongForCities[$label]; - $lat = round($lat, Piwik_UserCountry_LocationProvider::GEOGRAPHIC_COORD_PRECISION); - $long = round($long, Piwik_UserCountry_LocationProvider::GEOGRAPHIC_COORD_PRECISION); - - // set latitude + longitude metadata - $row->setMetadata('lat', $lat); - $row->setMetadata('long', $long); - } - } - } } diff --git a/plugins/UserCountry/functions.php b/plugins/UserCountry/functions.php index ab1ff7e26a3ba7053997177de070049a5bc0a07b..072c54030bfee370555d7c3f52b2402bec65dee3 100644 --- a/plugins/UserCountry/functions.php +++ b/plugins/UserCountry/functions.php @@ -92,7 +92,7 @@ function Piwik_UserCountry_getRegionName($label) return Piwik_Translate('General_Unknown'); } - list($regionCode, $countryCode) = explode(Piwik_UserCountry::LOCATION_SEPARATOR, $label); + list($regionCode, $countryCode) = explode(Piwik_UserCountry_Archiving::LOCATION_SEPARATOR, $label); return Piwik_UserCountry_LocationProvider_GeoIp::getRegionNameFromCodes($countryCode, $regionCode); } @@ -114,7 +114,7 @@ function Piwik_UserCountry_getPrettyRegionName($label) return Piwik_Translate('General_Unknown'); } - list($regionCode, $countryCode) = explode(Piwik_UserCountry::LOCATION_SEPARATOR, $label); + list($regionCode, $countryCode) = explode(Piwik_UserCountry_Archiving::LOCATION_SEPARATOR, $label); $result = Piwik_UserCountry_LocationProvider_GeoIp::getRegionNameFromCodes($countryCode, $regionCode); if ($countryCode != Piwik_Tracker_Visit::UNKNOWN_CODE && $countryCode != '') { @@ -143,7 +143,7 @@ function Piwik_UserCountry_getPrettyCityName($label) } // get city name, region code & country code - $parts = explode(Piwik_UserCountry::LOCATION_SEPARATOR, $label); + $parts = explode(Piwik_UserCountry_Archiving::LOCATION_SEPARATOR, $label); $cityName = $parts[0]; $regionCode = $parts[1]; $countryCode = $parts[2]; diff --git a/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referers.getCleanKeyword.xml b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referers.getCleanKeyword.xml new file mode 100644 index 0000000000000000000000000000000000000000..07f3ff9a02d6436a03e1ec57b46ca47f3a010d89 --- /dev/null +++ b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referers.getCleanKeyword.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <error message="Please specify a value for 'label'. + + --> To temporarily debug this error further, set $SHOW_ME_BACKTRACE=true; in ResponseBuilder.php" /> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referers.getKeywordNotDefinedString.xml b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referers.getKeywordNotDefinedString.xml new file mode 100644 index 0000000000000000000000000000000000000000..60b9a623a5848f56c2ee6a6dac2ce95a1a3d16a2 --- /dev/null +++ b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referers.getKeywordNotDefinedString.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result>Keyword not defined</result> \ No newline at end of file