2023-01-23 11:03:31 +01:00

295 lines
12 KiB
PHP

<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\Referrers;
use Exception;
use Piwik\Common;
use Piwik\Config;
use Piwik\DataArray;
use Piwik\Metrics;
class Archiver extends \Piwik\Plugin\Archiver
{
const SEARCH_ENGINES_RECORD_NAME = 'Referrers_keywordBySearchEngine';
const SOCIAL_NETWORKS_RECORD_NAME = 'Referrers_urlBySocialNetwork';
const KEYWORDS_RECORD_NAME = 'Referrers_searchEngineByKeyword';
const CAMPAIGNS_RECORD_NAME = 'Referrers_keywordByCampaign';
const WEBSITES_RECORD_NAME = 'Referrers_urlByWebsite';
const REFERRER_TYPE_RECORD_NAME = 'Referrers_type';
const METRIC_DISTINCT_SEARCH_ENGINE_RECORD_NAME = 'Referrers_distinctSearchEngines';
const METRIC_DISTINCT_SOCIAL_NETWORK_RECORD_NAME = 'Referrers_distinctSocialNetworks';
const METRIC_DISTINCT_KEYWORD_RECORD_NAME = 'Referrers_distinctKeywords';
const METRIC_DISTINCT_CAMPAIGN_RECORD_NAME = 'Referrers_distinctCampaigns';
const METRIC_DISTINCT_WEBSITE_RECORD_NAME = 'Referrers_distinctWebsites';
const METRIC_DISTINCT_URLS_RECORD_NAME = 'Referrers_distinctWebsitesUrls';
protected $columnToSortByBeforeTruncation;
protected $maximumRowsInDataTableLevelZero;
protected $maximumRowsInSubDataTable;
/**
* @var DataArray[] $arrays
*/
protected $arrays = array();
protected $distinctUrls = array();
function __construct($processor)
{
parent::__construct($processor);
$this->columnToSortByBeforeTruncation = Metrics::INDEX_NB_VISITS;
// Reading pre 2.0 config file settings
$this->maximumRowsInDataTableLevelZero = @Config::getInstance()->General['datatable_archiving_maximum_rows_referers'];
$this->maximumRowsInSubDataTable = @Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_referers'];
if (empty($this->maximumRowsInDataTableLevelZero)) {
$this->maximumRowsInDataTableLevelZero = Config::getInstance()->General['datatable_archiving_maximum_rows_referrers'];
$this->maximumRowsInSubDataTable = Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_referrers'];
}
}
public function aggregateDayReport()
{
foreach ($this->getRecordNames() as $record) {
$this->arrays[$record] = new DataArray();
}
$this->aggregateFromVisits(array("referer_type", "referer_name", "referer_keyword", "referer_url"));
$this->aggregateFromConversions(array("referer_type", "referer_name", "referer_keyword"));
$this->insertDayReports();
}
protected function getRecordNames()
{
return array(
self::REFERRER_TYPE_RECORD_NAME,
self::KEYWORDS_RECORD_NAME,
self::SEARCH_ENGINES_RECORD_NAME,
self::SOCIAL_NETWORKS_RECORD_NAME,
self::WEBSITES_RECORD_NAME,
self::CAMPAIGNS_RECORD_NAME,
);
}
protected function makeReferrerTypeNonEmpty(&$row)
{
if (empty($row['referer_type'])) {
$row['referer_type'] = Common::REFERRER_TYPE_DIRECT_ENTRY;
}
}
protected function aggregateVisitRow($row)
{
switch ($row['referer_type']) {
case Common::REFERRER_TYPE_SEARCH_ENGINE:
if (empty($row['referer_keyword'])) {
$row['referer_keyword'] = API::LABEL_KEYWORD_NOT_DEFINED;
}
$searchEnginesArray = $this->getDataArray(self::SEARCH_ENGINES_RECORD_NAME);
$searchEnginesArray->sumMetricsVisits($row['referer_name'], $row);
$searchEnginesArray->sumMetricsVisitsPivot($row['referer_name'], $row['referer_keyword'], $row);
$keywordsDataArray = $this->getDataArray(self::KEYWORDS_RECORD_NAME);
$keywordsDataArray->sumMetricsVisits($row['referer_keyword'], $row);
$keywordsDataArray->sumMetricsVisitsPivot($row['referer_keyword'], $row['referer_name'], $row);
break;
case Common::REFERRER_TYPE_SOCIAL_NETWORK:
$this->getDataArray(self::SOCIAL_NETWORKS_RECORD_NAME)->sumMetricsVisits($row['referer_name'], $row);
$this->getDataArray(self::SOCIAL_NETWORKS_RECORD_NAME)->sumMetricsVisitsPivot($row['referer_name'], $row['referer_url'], $row);
break;
case Common::REFERRER_TYPE_WEBSITE:
$this->getDataArray(self::WEBSITES_RECORD_NAME)->sumMetricsVisits($row['referer_name'], $row);
$this->getDataArray(self::WEBSITES_RECORD_NAME)->sumMetricsVisitsPivot($row['referer_name'], $row['referer_url'], $row);
$urlHash = substr(md5($row['referer_url']), 0, 10);
if (!isset($this->distinctUrls[$urlHash])) {
$this->distinctUrls[$urlHash] = true;
}
break;
case Common::REFERRER_TYPE_CAMPAIGN:
if (!empty($row['referer_keyword'])) {
$this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsVisitsPivot($row['referer_name'], $row['referer_keyword'], $row);
}
$this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsVisits($row['referer_name'], $row);
break;
case Common::REFERRER_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;
}
$this->getDataArray(self::REFERRER_TYPE_RECORD_NAME)->sumMetricsVisits($row['referer_type'], $row);
}
/**
* @param string $name
* @return DataArray
*/
protected function getDataArray($name)
{
return $this->arrays[$name];
}
protected function aggregateFromConversions($dimensions)
{
$query = $this->getLogAggregator()->queryConversionsByDimension($dimensions);
if ($query === false) {
return;
}
while ($row = $query->fetch()) {
$this->makeReferrerTypeNonEmpty($row);
$skipAggregateByType = $this->aggregateConversionRow($row);
if (!$skipAggregateByType) {
$this->getDataArray(self::REFERRER_TYPE_RECORD_NAME)->sumMetricsGoals($row['referer_type'], $row);
}
}
foreach ($this->arrays as $dataArray) {
$dataArray->enrichMetricsWithConversions();
}
}
protected function aggregateConversionRow($row)
{
$skipAggregateByType = false;
switch ($row['referer_type']) {
case Common::REFERRER_TYPE_SEARCH_ENGINE:
if (empty($row['referer_keyword'])) {
$row['referer_keyword'] = API::LABEL_KEYWORD_NOT_DEFINED;
}
$this->getDataArray(self::SEARCH_ENGINES_RECORD_NAME)->sumMetricsGoals($row['referer_name'], $row);
$this->getDataArray(self::KEYWORDS_RECORD_NAME)->sumMetricsGoals($row['referer_keyword'], $row);
break;
case Common::REFERRER_TYPE_SOCIAL_NETWORK:
$this->getDataArray(self::SOCIAL_NETWORKS_RECORD_NAME)->sumMetricsGoals($row['referer_name'], $row);
break;
case Common::REFERRER_TYPE_WEBSITE:
$this->getDataArray(self::WEBSITES_RECORD_NAME)->sumMetricsGoals($row['referer_name'], $row);
break;
case Common::REFERRER_TYPE_CAMPAIGN:
if (!empty($row['referer_keyword'])) {
$this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsGoalsPivot($row['referer_name'], $row['referer_keyword'], $row);
}
$this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->sumMetricsGoals($row['referer_name'], $row);
break;
case Common::REFERRER_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;
}
/**
* Records the daily stats (numeric or datatable blob) into the archive tables.
*/
protected function insertDayReports()
{
$this->insertDayNumericMetrics();
// insert DataTable reports
foreach ($this->getRecordNames() as $recordName) {
$blob = $this->getDataArray($recordName)->asDataTable()->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation);
$this->getProcessor()->insertBlobRecord($recordName, $blob);
}
}
protected function insertDayNumericMetrics()
{
$numericRecords = array(
self::METRIC_DISTINCT_SEARCH_ENGINE_RECORD_NAME => count($this->getDataArray(self::SEARCH_ENGINES_RECORD_NAME)->getDataArray()),
self::METRIC_DISTINCT_SOCIAL_NETWORK_RECORD_NAME => count($this->getDataArray(self::SOCIAL_NETWORKS_RECORD_NAME)->getDataArray()),
self::METRIC_DISTINCT_KEYWORD_RECORD_NAME => count($this->getDataArray(self::KEYWORDS_RECORD_NAME)->getDataArray()),
self::METRIC_DISTINCT_CAMPAIGN_RECORD_NAME => count($this->getDataArray(self::CAMPAIGNS_RECORD_NAME)->getDataArray()),
self::METRIC_DISTINCT_WEBSITE_RECORD_NAME => count($this->getDataArray(self::WEBSITES_RECORD_NAME)->getDataArray()),
self::METRIC_DISTINCT_URLS_RECORD_NAME => count($this->distinctUrls),
);
$this->getProcessor()->insertNumericRecords($numericRecords);
}
public function aggregateMultipleReports()
{
$dataTableToSum = $this->getRecordNames();
$columnsAggregationOperation = null;
$nameToCount = $this->getProcessor()->aggregateDataTableRecords(
$dataTableToSum,
$this->maximumRowsInDataTableLevelZero,
$this->maximumRowsInSubDataTable,
$this->columnToSortByBeforeTruncation,
$columnsAggregationOperation,
$columnsToRenameAfterAggregation = null,
$countRowsRecursive = array(self::WEBSITES_RECORD_NAME)
);
$mappingFromArchiveName = array(
self::METRIC_DISTINCT_SEARCH_ENGINE_RECORD_NAME =>
array('typeCountToUse' => 'level0',
'nameTableToUse' => self::SEARCH_ENGINES_RECORD_NAME,
),
self::METRIC_DISTINCT_SOCIAL_NETWORK_RECORD_NAME =>
array('typeCountToUse' => 'level0',
'nameTableToUse' => self::SOCIAL_NETWORKS_RECORD_NAME,
),
self::METRIC_DISTINCT_KEYWORD_RECORD_NAME =>
array('typeCountToUse' => 'level0',
'nameTableToUse' => self::KEYWORDS_RECORD_NAME,
),
self::METRIC_DISTINCT_CAMPAIGN_RECORD_NAME =>
array('typeCountToUse' => 'level0',
'nameTableToUse' => self::CAMPAIGNS_RECORD_NAME,
),
self::METRIC_DISTINCT_WEBSITE_RECORD_NAME =>
array('typeCountToUse' => 'level0',
'nameTableToUse' => self::WEBSITES_RECORD_NAME,
),
self::METRIC_DISTINCT_URLS_RECORD_NAME =>
array('typeCountToUse' => 'recursive',
'nameTableToUse' => self::WEBSITES_RECORD_NAME,
),
);
foreach ($mappingFromArchiveName as $name => $infoMapping) {
$nameTableToUse = $infoMapping['nameTableToUse'];
if ($infoMapping['typeCountToUse'] == 'recursive') {
$countValue = $nameToCount[$nameTableToUse]['recursive'] - $nameToCount[$nameTableToUse]['level0'];
} else {
$countValue = $nameToCount[$nameTableToUse]['level0'];
}
$this->getProcessor()->insertNumericRecord($name, $countValue);
}
}
/**
* @param $fields
*/
private function aggregateFromVisits($fields)
{
$query = $this->getLogAggregator()->queryVisitsByDimension($fields);
while ($row = $query->fetch()) {
$this->makeReferrerTypeNonEmpty($row);
$this->aggregateVisitRow($row);
}
}
}