Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'core/ArchiveProcessing.php')
-rw-r--r--core/ArchiveProcessing.php2027
1 files changed, 992 insertions, 1035 deletions
diff --git a/core/ArchiveProcessing.php b/core/ArchiveProcessing.php
index 17d2a32246..7ffa394ce9 100644
--- a/core/ArchiveProcessing.php
+++ b/core/ArchiveProcessing.php
@@ -1,10 +1,10 @@
<?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
* @package Piwik
*/
@@ -12,561 +12,545 @@
/**
* The ArchiveProcessing module is a module that reads the Piwik logs from the DB and
* compute all the reports, which are then stored in the database.
- *
+ *
* The ArchiveProcessing class is used by the Archive object to make sure the given Archive is processed and available in the DB.
- *
+ *
* A record in the Database for a given report is defined by
- * - idarchive = unique ID that is associated to all the data of this archive (idsite+period+date)
- * - idsite = the ID of the website
- * - date1 = starting day of the period
- * - date2 = ending day of the period
- * - period = integer that defines the period (day/week/etc.). @see period::getId()
+ * - idarchive = unique ID that is associated to all the data of this archive (idsite+period+date)
+ * - idsite = the ID of the website
+ * - date1 = starting day of the period
+ * - date2 = ending day of the period
+ * - period = integer that defines the period (day/week/etc.). @see period::getId()
* - ts_archived = timestamp when the archive was processed (UTC)
- * - name = the name of the report (ex: uniq_visitors or search_keywords_by_search_engines)
- * - value = the actual data
- *
+ * - name = the name of the report (ex: uniq_visitors or search_keywords_by_search_engines)
+ * - value = the actual data
+ *
* @package Piwik
* @subpackage Piwik_ArchiveProcessing
*/
abstract class Piwik_ArchiveProcessing
{
- /**
- * Flag stored at the end of the archiving
- *
- * @var int
- */
- const DONE_OK = 1;
-
- /**
- * Flag stored at the start of the archiving
- * When requesting an Archive, we make sure that non-finished archive are not considered valid
- *
- * @var int
- */
- const DONE_ERROR = 2;
-
- /**
- * Flag indicates the archive is over a period that is not finished, eg. the current day, current week, etc.
- * Archives flagged will be regularly purged from the DB.
- *
- * @var int
- */
- const DONE_OK_TEMPORARY = 3;
-
- /**
- * A row is created to lock an idarchive for the current archive being processed
- * @var string
- */
- const PREFIX_SQL_LOCK = "locked_";
-
- /**
- * Idarchive in the DB for the requested archive
- *
- * @var int
- */
- protected $idArchive;
-
- /**
- * Period id @see Piwik_Period::getId()
- *
- * @var int
- */
- protected $periodId;
-
- /**
- * Timestamp for the first date of the period
- *
- * @var int unix timestamp
- */
- protected $timestampDateStart = null;
-
- /**
- * Starting date of the archive
- *
- * @var Piwik_Date
- */
- protected $dateStart;
-
- /**
- * Ending date of the archive
- *
- * @var Piwik_Date
- */
- protected $dateEnd;
-
- /**
- * Object used to generate (depending on the $dateStart) the name of the DB table to use to store numeric values
- *
- * @var Piwik_TablePartitioning
- */
- protected $tableArchiveNumeric;
-
- /**
- * Object used to generate (depending on the $dateStart) the name of the DB table to use to store numeric values
- *
- * @var Piwik_TablePartitioning
- */
- protected $tableArchiveBlob;
-
- /**
- * Minimum timestamp looked at for processed archives
- *
- * @var int
- */
- protected $minDatetimeArchiveProcessedUTC = false;
-
- /**
- * Compress blobs
- *
- * @var bool
- */
- protected $compressBlob;
-
- /**
- * Is the current archive temporary. ie.
- * - today
- * - current week / month / year
- */
- protected $temporaryArchive;
-
- /**
- * Id of the current site
- * Can be accessed by plugins (that is why it's public)
- *
- * @var int
- */
- public $idsite = null;
-
- /**
- * Period of the current archive
- * Can be accessed by plugins (that is why it's public)
- *
- * @var Piwik_Period
- */
- public $period = null;
-
- /**
- * Site of the current archive
- * Can be accessed by plugins (that is why it's public)
- *
- * @var Piwik_Site
- */
- public $site = null;
-
- /**
- * @var Piwik_Segment
- */
- protected $segment = null;
-
- /**
- * Current time.
- * This value is cached.
- *
- * @var int
- */
- public $time = null;
-
- /**
- * Starting datetime in UTC
- *
- * @var string
- */
- public $startDatetimeUTC;
-
- /**
- * Ending date in UTC
- *
- * @var string
- */
- public $strDateEnd;
-
- /**
- * Name of the DB table _log_visit
- *
- * @var string
- */
- public $logTable;
-
- /**
- * When set to true, we always archive, even if the archive is already available.
- * You can change this settings automatically in the config/global.ini.php always_archive_data under the [Debug] section
- *
- * @var bool
- */
- public $debugAlwaysArchive = false;
-
- /**
- * If the archive has at least 1 visit, this is set to true.
- *
- * @var bool
- */
- public $isThereSomeVisits = null;
-
- protected $startTimestampUTC;
- protected $endTimestampUTC;
-
- /**
- * Flag that will forcefully disable the archiving process. Only set by the tests.
- */
- public static $forceDisableArchiving = false;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->time = time();
- }
-
- /**
- * Returns the Piwik_ArchiveProcessing_Day or Piwik_ArchiveProcessing_Period object
- * depending on $name period string
- *
- * @param string $name day|week|month|year
- * @throws Exception
- * @return Piwik_ArchiveProcessing Piwik_ArchiveProcessing_Day|Piwik_ArchiveProcessing_Period
- */
- static function factory($name)
- {
- switch($name)
- {
- case 'day':
- $process = new Piwik_ArchiveProcessing_Day();
- $process->debugAlwaysArchive = Piwik_Config::getInstance()->Debug['always_archive_data_day'];
- break;
-
- case 'week':
- case 'month':
- case 'year':
- $process = new Piwik_ArchiveProcessing_Period();
- $process->debugAlwaysArchive = Piwik_Config::getInstance()->Debug['always_archive_data_period'];
- break;
-
- case 'range':
- $process = new Piwik_ArchiveProcessing_Period();
- $process->debugAlwaysArchive = Piwik_Config::getInstance()->Debug['always_archive_data_range'];
- break;
-
- default:
- throw new Exception("Unknown Archiving period specified '$name'");
- break;
- }
- return $process;
- }
-
- const OPTION_TODAY_ARCHIVE_TTL = 'todayArchiveTimeToLive';
- const OPTION_BROWSER_TRIGGER_ARCHIVING = 'enableBrowserTriggerArchiving';
-
- static public function getCoreMetrics()
- {
- return array(
- 'nb_uniq_visitors',
- 'nb_visits',
- 'nb_actions',
- 'sum_visit_length',
- 'bounce_count',
- 'nb_visits_converted',
- );
- }
-
- static public function setTodayArchiveTimeToLive($timeToLiveSeconds)
- {
- $timeToLiveSeconds = (int)$timeToLiveSeconds;
- if($timeToLiveSeconds <= 0)
- {
- throw new Exception(Piwik_TranslateException('General_ExceptionInvalidArchiveTimeToLive'));
- }
- Piwik_SetOption(self::OPTION_TODAY_ARCHIVE_TTL, $timeToLiveSeconds, $autoload = true);
- }
-
- static public function getTodayArchiveTimeToLive()
- {
- $timeToLive = Piwik_GetOption(self::OPTION_TODAY_ARCHIVE_TTL);
- if($timeToLive !== false)
- {
- return $timeToLive;
- }
- return Piwik_Config::getInstance()->General['time_before_today_archive_considered_outdated'];
- }
-
- static public function setBrowserTriggerArchiving($enabled)
- {
- if(!is_bool($enabled))
- {
- throw new Exception('Browser trigger archiving must be set to true or false.');
- }
- Piwik_SetOption(self::OPTION_BROWSER_TRIGGER_ARCHIVING, (int)$enabled, $autoload = true);
- Piwik_Tracker_Cache::clearCacheGeneral();
- }
-
- static public function isBrowserTriggerArchivingEnabled()
- {
- $browserArchivingEnabled = Piwik_GetOption(self::OPTION_BROWSER_TRIGGER_ARCHIVING);
- if($browserArchivingEnabled !== false)
- {
- return (bool)$browserArchivingEnabled;
- }
- return (bool)Piwik_Config::getInstance()->General['enable_browser_archiving_triggering'];
- }
-
- public function getIdArchive()
- {
- return $this->idArchive;
- }
-
- /**
- * Sets object attributes that will be used throughout the process
- */
- public function init()
- {
- $this->idsite = $this->site->getId();
- $this->periodId = $this->period->getId();
-
- $this->initDates();
-
- $this->tableArchiveNumeric = self::makeNumericArchiveTable($this->period);
- $this->tableArchiveBlob = self::makeBlobArchiveTable($this->period);
-
- $this->minDatetimeArchiveProcessedUTC = $this->getMinTimeArchivedProcessed();
- $db = Zend_Registry::get('db');
- $this->compressBlob = $db->hasBlobDataType();
- }
-
- /**
- * The archive processing classes have features that might be useful for live querying;
- * In particular, Piwik_ArchiveProcessing_Day::query*. In order to reuse those methods
- * outside the actual archiving or to reuse archiving code for live querying, an instance
- * of archive processing has to be faked.
- *
- * For example, this code can be used in an API method:
- * $archiveProcessing = new Piwik_ArchiveProcessing_Day();
- * $archiveProcessing->setSite(new Piwik_Site($idSite));
- * $archiveProcessing->setPeriod(Piwik_Period::advancedFactory($period, $date));
- * $archiveProcessing->setSegment(new Piwik_Segment($segment, $idSite));
- * $archiveProcessing->initForLiveUsage();
- * Then, either use $archiveProcessing->query* or pass the instance to the archiving
- * code of the plugin. Note that even though we use Piwik_ArchiveProcessing_Day, this
- * works for any $period and $date that has been passed to the API.
- */
- public function initForLiveUsage() {
- $this->idsite = $this->site->getId();
- $this->initDates();
- }
-
- private function initDates() {
- $dateStartLocalTimezone = $this->period->getDateStart();
- $dateEndLocalTimezone = $this->period->getDateEnd();
-
- $dateStartUTC = $dateStartLocalTimezone->setTimezone($this->site->getTimezone());
- $dateEndUTC = $dateEndLocalTimezone->setTimezone($this->site->getTimezone());
- $this->startDatetimeUTC = $dateStartUTC->getDateStartUTC();
- $this->endDatetimeUTC = $dateEndUTC->getDateEndUTC();
- $this->startTimestampUTC = $dateStartUTC->getTimestamp();
- $this->endTimestampUTC = strtotime($this->endDatetimeUTC);
- }
-
- /**
- * Utility function which creates a TablePartitioning instance for the numeric
- * archive data of a given period.
- *
- * @param Piwik_Period $period The time period of the archive data.
- * @return Piwik_TablePartitioning_Monthly
- */
- public static function makeNumericArchiveTable($period)
- {
- $result = new Piwik_TablePartitioning_Monthly('archive_numeric');
- $result->setTimestamp($period->getDateStart()->getTimestamp());
- return $result;
- }
-
- /**
- * Utility function which creates a TablePartitioning instance for the blob
- * archive data of a given period.
- *
- * @param Piwik_Period $period The time period of the archive data.
- * @return Piwik_TablePartitioning_Monthly
- */
- public static function makeBlobArchiveTable($period)
- {
- $result = new Piwik_TablePartitioning_Monthly('archive_blob');
- $result->setTimestamp($period->getDateStart()->getTimestamp());
- return $result;
- }
-
- public function getStartDatetimeUTC()
- {
- return $this->startDatetimeUTC;
- }
-
- public function getEndDatetimeUTC()
- {
- return $this->endDatetimeUTC;
- }
-
- public function isArchiveTemporary()
- {
- return $this->temporaryArchive;
- }
-
- /**
- * Returns the minimum archive processed datetime to look at
- *
- * @return string Datetime string, or false if must look at any archive available
- */
- public function getMinTimeArchivedProcessed()
- {
- $this->temporaryArchive = false;
- // if the current archive is a DAY and if it's today,
- // we set this minDatetimeArchiveProcessedUTC that defines the lifetime value of today's archive
- if( $this->period->getNumberOfSubperiods() == 0
- && ($this->startTimestampUTC <= $this->time && $this->endTimestampUTC > $this->time)
- )
- {
- $this->temporaryArchive = true;
- $minDatetimeArchiveProcessedUTC = $this->time - self::getTodayArchiveTimeToLive();
- // see #1150; if new archives are not triggered from the browser,
- // we still want to try and return the latest archive available for today (rather than return nothing)
- if($this->isArchivingDisabled())
- {
- return false;
- }
- }
- // - if the period we are looking for is finished, we look for a ts_archived that
- // is greater than the last day of the archive
- elseif($this->endTimestampUTC <= $this->time)
- {
- $minDatetimeArchiveProcessedUTC = $this->endTimestampUTC;
- }
- // - if the period we're looking for is not finished, we look for a recent enough archive
- else
- {
- $this->temporaryArchive = true;
-
- // We choose to only look at archives that are newer than the specified timeout
- $minDatetimeArchiveProcessedUTC = $this->time - self::getTodayArchiveTimeToLive();
-
- // However, if archiving is disabled for this request, we shall
- // accept any archive that was processed today after 00:00:01 this morning
- if($this->isArchivingDisabled())
- {
- $timezone = $this->site->getTimezone();
- $minDatetimeArchiveProcessedUTC = Piwik_Date::factory(Piwik_Date::factory('now', $timezone)->getDateStartUTC())->setTimezone($timezone)->getTimestamp();
- }
- }
- return $minDatetimeArchiveProcessedUTC;
- }
-
- /**
- * This method returns the idArchive ; if necessary, it triggers the archiving process.
- *
- * If the archive was not processed yet, it will launch the archiving process.
- * If the current archive needs sub-archives (eg. a month archive needs all the days archive)
- * it will recursively launch the archiving (using this loadArchive() on the sub-periods)
- *
- * @return int|false The idarchive of the archive, false if the archive is not archived yet
- */
- public function loadArchive()
- {
- $this->init();
- if($this->debugAlwaysArchive)
- {
- return false;
- }
- $this->idArchive = $this->isArchived();
-
- if($this->idArchive === false)
- {
- return false;
- }
- return $this->idArchive;
- }
-
- /**
- * @see loadArchive()
- */
- public function launchArchiving()
- {
- if (!Piwik::getArchiveProcessingLock($this->idsite, $this->period, $this->segment))
- {
- Piwik::log('Unable to get lock for idSite = ' . $this->idsite
- . ', period = ' . $this->period->getLabel()
- . ', UTC datetime [' . $this->startDatetimeUTC . ' -> ' . $this->endDatetimeUTC . ' ]...');
- return;
- }
-
- $this->initCompute();
- $this->compute();
- $this->postCompute();
- // we execute again the isArchived that does some initialization work
- $this->idArchive = $this->isArchived();
- Piwik::releaseArchiveProcessingLock($this->idsite, $this->period, $this->segment);
- }
-
- /**
- * This methods reads the subperiods if necessary,
- * and computes the archive of the current period.
- */
- abstract protected function compute();
-
- abstract public function isThereSomeVisits();
-
- /**
- * Returns the name of the archive field used to tell the status of an archive, (ie,
- * whether the archive was created successfully or not).
- *
- * @param bool $flagArchiveAsAllPlugins
- * @return string
- */
- public function getDoneStringFlag($flagArchiveAsAllPlugins = false)
- {
- return self::getDoneStringFlagFor(
- $this->getSegment(), $this->period, $this->getRequestedReport(), $flagArchiveAsAllPlugins);
- }
-
- /**
- * Returns the name of the archive field used to tell the status of an archive, (ie,
- * whether the archive was created successfully or not).
- *
- * @param Piwik_Segment $segment
- * @param Piwik_Period $period
- * @param string $requestedReport
- * @param bool $flagArchiveAsAllPlugins
- * @return string
- */
- public static function getDoneStringFlagFor($segment, $period, $requestedReport, $flagArchiveAsAllPlugins = false)
- {
- $segmentHash = $segment->getHash();
- if(!self::shouldProcessReportsAllPluginsFor($segment, $period))
- {
- $pluginProcessed = self::getPluginBeingProcessed($requestedReport);
- if(!Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginProcessed)
- || $flagArchiveAsAllPlugins
- )
- {
- $pluginProcessed = 'all';
- }
- $segmentHash .= '.'.$pluginProcessed;
- }
- return 'done' . $segmentHash;
- }
-
- /**
- * Init the object before launching the real archive processing
- */
- protected function initCompute()
- {
- $this->loadNextIdarchive();
- $done = $this->getDoneStringFlag();
- $this->insertNumericRecord($done, Piwik_ArchiveProcessing::DONE_ERROR);
-
- // Can be removed when GeoIp is in core
- $this->logTable = Piwik_Common::prefixTable('log_visit');
-
- $temporary = 'definitive archive';
- if($this->isArchiveTemporary())
- {
- $temporary = 'temporary archive';
- }
+ /**
+ * Flag stored at the end of the archiving
+ *
+ * @var int
+ */
+ const DONE_OK = 1;
+
+ /**
+ * Flag stored at the start of the archiving
+ * When requesting an Archive, we make sure that non-finished archive are not considered valid
+ *
+ * @var int
+ */
+ const DONE_ERROR = 2;
+
+ /**
+ * Flag indicates the archive is over a period that is not finished, eg. the current day, current week, etc.
+ * Archives flagged will be regularly purged from the DB.
+ *
+ * @var int
+ */
+ const DONE_OK_TEMPORARY = 3;
+
+ /**
+ * A row is created to lock an idarchive for the current archive being processed
+ * @var string
+ */
+ const PREFIX_SQL_LOCK = "locked_";
+
+ /**
+ * Idarchive in the DB for the requested archive
+ *
+ * @var int
+ */
+ protected $idArchive;
+
+ /**
+ * Period id @see Piwik_Period::getId()
+ *
+ * @var int
+ */
+ protected $periodId;
+
+ /**
+ * Timestamp for the first date of the period
+ *
+ * @var int unix timestamp
+ */
+ protected $timestampDateStart = null;
+
+ /**
+ * Starting date of the archive
+ *
+ * @var Piwik_Date
+ */
+ protected $dateStart;
+
+ /**
+ * Ending date of the archive
+ *
+ * @var Piwik_Date
+ */
+ protected $dateEnd;
+
+ /**
+ * Object used to generate (depending on the $dateStart) the name of the DB table to use to store numeric values
+ *
+ * @var Piwik_TablePartitioning
+ */
+ protected $tableArchiveNumeric;
+
+ /**
+ * Object used to generate (depending on the $dateStart) the name of the DB table to use to store numeric values
+ *
+ * @var Piwik_TablePartitioning
+ */
+ protected $tableArchiveBlob;
+
+ /**
+ * Minimum timestamp looked at for processed archives
+ *
+ * @var int
+ */
+ protected $minDatetimeArchiveProcessedUTC = false;
+
+ /**
+ * Compress blobs
+ *
+ * @var bool
+ */
+ protected $compressBlob;
+
+ /**
+ * Is the current archive temporary. ie.
+ * - today
+ * - current week / month / year
+ */
+ protected $temporaryArchive;
+
+ /**
+ * Id of the current site
+ * Can be accessed by plugins (that is why it's public)
+ *
+ * @var int
+ */
+ public $idsite = null;
+
+ /**
+ * Period of the current archive
+ * Can be accessed by plugins (that is why it's public)
+ *
+ * @var Piwik_Period
+ */
+ public $period = null;
+
+ /**
+ * Site of the current archive
+ * Can be accessed by plugins (that is why it's public)
+ *
+ * @var Piwik_Site
+ */
+ public $site = null;
+
+ /**
+ * @var Piwik_Segment
+ */
+ protected $segment = null;
+
+ /**
+ * Current time.
+ * This value is cached.
+ *
+ * @var int
+ */
+ public $time = null;
+
+ /**
+ * Starting datetime in UTC
+ *
+ * @var string
+ */
+ public $startDatetimeUTC;
+
+ /**
+ * Ending date in UTC
+ *
+ * @var string
+ */
+ public $strDateEnd;
+
+ /**
+ * Name of the DB table _log_visit
+ *
+ * @var string
+ */
+ public $logTable;
+
+ /**
+ * When set to true, we always archive, even if the archive is already available.
+ * You can change this settings automatically in the config/global.ini.php always_archive_data under the [Debug] section
+ *
+ * @var bool
+ */
+ public $debugAlwaysArchive = false;
+
+ /**
+ * If the archive has at least 1 visit, this is set to true.
+ *
+ * @var bool
+ */
+ public $isThereSomeVisits = null;
+
+ protected $startTimestampUTC;
+ protected $endTimestampUTC;
+
+ /**
+ * Flag that will forcefully disable the archiving process. Only set by the tests.
+ */
+ public static $forceDisableArchiving = false;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->time = time();
+ }
+
+ /**
+ * Returns the Piwik_ArchiveProcessing_Day or Piwik_ArchiveProcessing_Period object
+ * depending on $name period string
+ *
+ * @param string $name day|week|month|year
+ * @throws Exception
+ * @return Piwik_ArchiveProcessing Piwik_ArchiveProcessing_Day|Piwik_ArchiveProcessing_Period
+ */
+ static function factory($name)
+ {
+ switch ($name) {
+ case 'day':
+ $process = new Piwik_ArchiveProcessing_Day();
+ $process->debugAlwaysArchive = Piwik_Config::getInstance()->Debug['always_archive_data_day'];
+ break;
+
+ case 'week':
+ case 'month':
+ case 'year':
+ $process = new Piwik_ArchiveProcessing_Period();
+ $process->debugAlwaysArchive = Piwik_Config::getInstance()->Debug['always_archive_data_period'];
+ break;
+
+ case 'range':
+ $process = new Piwik_ArchiveProcessing_Period();
+ $process->debugAlwaysArchive = Piwik_Config::getInstance()->Debug['always_archive_data_range'];
+ break;
+
+ default:
+ throw new Exception("Unknown Archiving period specified '$name'");
+ break;
+ }
+ return $process;
+ }
+
+ const OPTION_TODAY_ARCHIVE_TTL = 'todayArchiveTimeToLive';
+ const OPTION_BROWSER_TRIGGER_ARCHIVING = 'enableBrowserTriggerArchiving';
+
+ static public function getCoreMetrics()
+ {
+ return array(
+ 'nb_uniq_visitors',
+ 'nb_visits',
+ 'nb_actions',
+ 'sum_visit_length',
+ 'bounce_count',
+ 'nb_visits_converted',
+ );
+ }
+
+ static public function setTodayArchiveTimeToLive($timeToLiveSeconds)
+ {
+ $timeToLiveSeconds = (int)$timeToLiveSeconds;
+ if ($timeToLiveSeconds <= 0) {
+ throw new Exception(Piwik_TranslateException('General_ExceptionInvalidArchiveTimeToLive'));
+ }
+ Piwik_SetOption(self::OPTION_TODAY_ARCHIVE_TTL, $timeToLiveSeconds, $autoload = true);
+ }
+
+ static public function getTodayArchiveTimeToLive()
+ {
+ $timeToLive = Piwik_GetOption(self::OPTION_TODAY_ARCHIVE_TTL);
+ if ($timeToLive !== false) {
+ return $timeToLive;
+ }
+ return Piwik_Config::getInstance()->General['time_before_today_archive_considered_outdated'];
+ }
+
+ static public function setBrowserTriggerArchiving($enabled)
+ {
+ if (!is_bool($enabled)) {
+ throw new Exception('Browser trigger archiving must be set to true or false.');
+ }
+ Piwik_SetOption(self::OPTION_BROWSER_TRIGGER_ARCHIVING, (int)$enabled, $autoload = true);
+ Piwik_Tracker_Cache::clearCacheGeneral();
+ }
+
+ static public function isBrowserTriggerArchivingEnabled()
+ {
+ $browserArchivingEnabled = Piwik_GetOption(self::OPTION_BROWSER_TRIGGER_ARCHIVING);
+ if ($browserArchivingEnabled !== false) {
+ return (bool)$browserArchivingEnabled;
+ }
+ return (bool)Piwik_Config::getInstance()->General['enable_browser_archiving_triggering'];
+ }
+
+ public function getIdArchive()
+ {
+ return $this->idArchive;
+ }
+
+ /**
+ * Sets object attributes that will be used throughout the process
+ */
+ public function init()
+ {
+ $this->idsite = $this->site->getId();
+ $this->periodId = $this->period->getId();
+
+ $this->initDates();
+
+ $this->tableArchiveNumeric = self::makeNumericArchiveTable($this->period);
+ $this->tableArchiveBlob = self::makeBlobArchiveTable($this->period);
+
+ $this->minDatetimeArchiveProcessedUTC = $this->getMinTimeArchivedProcessed();
+ $db = Zend_Registry::get('db');
+ $this->compressBlob = $db->hasBlobDataType();
+ }
+
+ /**
+ * The archive processing classes have features that might be useful for live querying;
+ * In particular, Piwik_ArchiveProcessing_Day::query*. In order to reuse those methods
+ * outside the actual archiving or to reuse archiving code for live querying, an instance
+ * of archive processing has to be faked.
+ *
+ * For example, this code can be used in an API method:
+ * $archiveProcessing = new Piwik_ArchiveProcessing_Day();
+ * $archiveProcessing->setSite(new Piwik_Site($idSite));
+ * $archiveProcessing->setPeriod(Piwik_Period::advancedFactory($period, $date));
+ * $archiveProcessing->setSegment(new Piwik_Segment($segment, $idSite));
+ * $archiveProcessing->initForLiveUsage();
+ * Then, either use $archiveProcessing->query* or pass the instance to the archiving
+ * code of the plugin. Note that even though we use Piwik_ArchiveProcessing_Day, this
+ * works for any $period and $date that has been passed to the API.
+ */
+ public function initForLiveUsage()
+ {
+ $this->idsite = $this->site->getId();
+ $this->initDates();
+ }
+
+ private function initDates()
+ {
+ $dateStartLocalTimezone = $this->period->getDateStart();
+ $dateEndLocalTimezone = $this->period->getDateEnd();
+
+ $dateStartUTC = $dateStartLocalTimezone->setTimezone($this->site->getTimezone());
+ $dateEndUTC = $dateEndLocalTimezone->setTimezone($this->site->getTimezone());
+ $this->startDatetimeUTC = $dateStartUTC->getDateStartUTC();
+ $this->endDatetimeUTC = $dateEndUTC->getDateEndUTC();
+ $this->startTimestampUTC = $dateStartUTC->getTimestamp();
+ $this->endTimestampUTC = strtotime($this->endDatetimeUTC);
+ }
+
+ /**
+ * Utility function which creates a TablePartitioning instance for the numeric
+ * archive data of a given period.
+ *
+ * @param Piwik_Period $period The time period of the archive data.
+ * @return Piwik_TablePartitioning_Monthly
+ */
+ public static function makeNumericArchiveTable($period)
+ {
+ $result = new Piwik_TablePartitioning_Monthly('archive_numeric');
+ $result->setTimestamp($period->getDateStart()->getTimestamp());
+ return $result;
+ }
+
+ /**
+ * Utility function which creates a TablePartitioning instance for the blob
+ * archive data of a given period.
+ *
+ * @param Piwik_Period $period The time period of the archive data.
+ * @return Piwik_TablePartitioning_Monthly
+ */
+ public static function makeBlobArchiveTable($period)
+ {
+ $result = new Piwik_TablePartitioning_Monthly('archive_blob');
+ $result->setTimestamp($period->getDateStart()->getTimestamp());
+ return $result;
+ }
+
+ public function getStartDatetimeUTC()
+ {
+ return $this->startDatetimeUTC;
+ }
+
+ public function getEndDatetimeUTC()
+ {
+ return $this->endDatetimeUTC;
+ }
+
+ public function isArchiveTemporary()
+ {
+ return $this->temporaryArchive;
+ }
+
+ /**
+ * Returns the minimum archive processed datetime to look at
+ *
+ * @return string Datetime string, or false if must look at any archive available
+ */
+ public function getMinTimeArchivedProcessed()
+ {
+ $this->temporaryArchive = false;
+ // if the current archive is a DAY and if it's today,
+ // we set this minDatetimeArchiveProcessedUTC that defines the lifetime value of today's archive
+ if ($this->period->getNumberOfSubperiods() == 0
+ && ($this->startTimestampUTC <= $this->time && $this->endTimestampUTC > $this->time)
+ ) {
+ $this->temporaryArchive = true;
+ $minDatetimeArchiveProcessedUTC = $this->time - self::getTodayArchiveTimeToLive();
+ // see #1150; if new archives are not triggered from the browser,
+ // we still want to try and return the latest archive available for today (rather than return nothing)
+ if ($this->isArchivingDisabled()) {
+ return false;
+ }
+ } // - if the period we are looking for is finished, we look for a ts_archived that
+ // is greater than the last day of the archive
+ elseif ($this->endTimestampUTC <= $this->time) {
+ $minDatetimeArchiveProcessedUTC = $this->endTimestampUTC;
+ } // - if the period we're looking for is not finished, we look for a recent enough archive
+ else {
+ $this->temporaryArchive = true;
+
+ // We choose to only look at archives that are newer than the specified timeout
+ $minDatetimeArchiveProcessedUTC = $this->time - self::getTodayArchiveTimeToLive();
+
+ // However, if archiving is disabled for this request, we shall
+ // accept any archive that was processed today after 00:00:01 this morning
+ if ($this->isArchivingDisabled()) {
+ $timezone = $this->site->getTimezone();
+ $minDatetimeArchiveProcessedUTC = Piwik_Date::factory(Piwik_Date::factory('now', $timezone)->getDateStartUTC())->setTimezone($timezone)->getTimestamp();
+ }
+ }
+ return $minDatetimeArchiveProcessedUTC;
+ }
+
+ /**
+ * This method returns the idArchive ; if necessary, it triggers the archiving process.
+ *
+ * If the archive was not processed yet, it will launch the archiving process.
+ * If the current archive needs sub-archives (eg. a month archive needs all the days archive)
+ * it will recursively launch the archiving (using this loadArchive() on the sub-periods)
+ *
+ * @return int|false The idarchive of the archive, false if the archive is not archived yet
+ */
+ public function loadArchive()
+ {
+ $this->init();
+ if ($this->debugAlwaysArchive) {
+ return false;
+ }
+ $this->idArchive = $this->isArchived();
+
+ if ($this->idArchive === false) {
+ return false;
+ }
+ return $this->idArchive;
+ }
+
+ /**
+ * @see loadArchive()
+ */
+ public function launchArchiving()
+ {
+ if (!Piwik::getArchiveProcessingLock($this->idsite, $this->period, $this->segment)) {
+ Piwik::log('Unable to get lock for idSite = ' . $this->idsite
+ . ', period = ' . $this->period->getLabel()
+ . ', UTC datetime [' . $this->startDatetimeUTC . ' -> ' . $this->endDatetimeUTC . ' ]...');
+ return;
+ }
+
+ $this->initCompute();
+ $this->compute();
+ $this->postCompute();
+ // we execute again the isArchived that does some initialization work
+ $this->idArchive = $this->isArchived();
+ Piwik::releaseArchiveProcessingLock($this->idsite, $this->period, $this->segment);
+ }
+
+ /**
+ * This methods reads the subperiods if necessary,
+ * and computes the archive of the current period.
+ */
+ abstract protected function compute();
+
+ abstract public function isThereSomeVisits();
+
+ /**
+ * Returns the name of the archive field used to tell the status of an archive, (ie,
+ * whether the archive was created successfully or not).
+ *
+ * @param bool $flagArchiveAsAllPlugins
+ * @return string
+ */
+ public function getDoneStringFlag($flagArchiveAsAllPlugins = false)
+ {
+ return self::getDoneStringFlagFor(
+ $this->getSegment(), $this->period, $this->getRequestedReport(), $flagArchiveAsAllPlugins);
+ }
+
+ /**
+ * Returns the name of the archive field used to tell the status of an archive, (ie,
+ * whether the archive was created successfully or not).
+ *
+ * @param Piwik_Segment $segment
+ * @param Piwik_Period $period
+ * @param string $requestedReport
+ * @param bool $flagArchiveAsAllPlugins
+ * @return string
+ */
+ public static function getDoneStringFlagFor($segment, $period, $requestedReport, $flagArchiveAsAllPlugins = false)
+ {
+ $segmentHash = $segment->getHash();
+ if (!self::shouldProcessReportsAllPluginsFor($segment, $period)) {
+ $pluginProcessed = self::getPluginBeingProcessed($requestedReport);
+ if (!Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginProcessed)
+ || $flagArchiveAsAllPlugins
+ ) {
+ $pluginProcessed = 'all';
+ }
+ $segmentHash .= '.' . $pluginProcessed;
+ }
+ return 'done' . $segmentHash;
+ }
+
+ /**
+ * Init the object before launching the real archive processing
+ */
+ protected function initCompute()
+ {
+ $this->loadNextIdarchive();
+ $done = $this->getDoneStringFlag();
+ $this->insertNumericRecord($done, Piwik_ArchiveProcessing::DONE_ERROR);
+
+ // Can be removed when GeoIp is in core
+ $this->logTable = Piwik_Common::prefixTable('log_visit');
+
+ $temporary = 'definitive archive';
+ if ($this->isArchiveTemporary()) {
+ $temporary = 'temporary archive';
+ }
Piwik::log(sprintf("'%s, idSite = %d (%s), segment '%s', report = '%s', UTC datetime [%s -> %s]",
$this->period->getLabel(),
$this->idsite,
@@ -576,518 +560,491 @@ abstract class Piwik_ArchiveProcessing
$this->startDatetimeUTC,
$this->endTimestampUTC
));
- }
-
- /**
- * Post processing called at the end of the main archive processing.
- * Makes sure the new archive is marked as "successful" in the DB
- *
- * We also try to delete some stuff from memory but really there is still a lot...
- */
- protected function postCompute()
- {
- // delete the first done = ERROR
- $done = $this->getDoneStringFlag();
- Piwik_Query("DELETE FROM ".$this->tableArchiveNumeric->getTableName()."
- WHERE idarchive = ? AND (name = '".$done."' OR name LIKE '".self::PREFIX_SQL_LOCK."%')",
- array($this->idArchive)
- );
-
- $flag = Piwik_ArchiveProcessing::DONE_OK;
- if($this->isArchiveTemporary())
- {
- $flag = Piwik_ArchiveProcessing::DONE_OK_TEMPORARY;
- }
- $this->insertNumericRecord($done, $flag);
- }
-
- /**
- * Returns the name of the numeric table where the archive numeric values are stored
- *
- * @return string
- */
- public function getTableArchiveNumericName()
- {
- return $this->tableArchiveNumeric->getTableName();
- }
-
- /**
- * Returns the name of the blob table where the archive blob values are stored
- *
- * @return string
- */
- public function getTableArchiveBlobName()
- {
- return $this->tableArchiveBlob->getTableName();
- }
-
- /**
- * Set the period
- *
- * @param Piwik_Period $period
- */
- public function setPeriod( Piwik_Period $period )
- {
- $this->period = $period;
- }
-
- public function setSegment( Piwik_Segment $segment)
- {
- $this->segment = $segment;
- }
-
- public function getSegment()
- {
- return $this->segment;
- }
- /**
- * Set the site
- *
- * @param Piwik_Site $site
- */
- public function setSite( Piwik_Site $site )
- {
- $this->site = $site;
- }
-
- public function setRequestedReport($requestedReport)
- {
- $this->requestedReport = $requestedReport;
- }
-
- protected function getRequestedReport()
- {
- return $this->requestedReport;
- }
-
- static public function getPluginBeingProcessed( $requestedReport )
- {
- $plugin = substr($requestedReport, 0, strpos($requestedReport, '_'));
- if(empty($plugin)
- || !Piwik_PluginsManager::getInstance()->isPluginActivated($plugin))
- {
- $pluginStr = empty($plugin) ? '' : "($plugin)";
- throw new Exception("Error: The report '$requestedReport' was requested but it is not available at this stage. You may also disable the related plugin $pluginStr to avoid this error.");
- }
- return $plugin;
- }
-
- /**
- * Returns the timestamp of the first date of the period
- *
- * @return int
- */
- public function getTimestampStartDate()
- {
- return $this->timestampDateStart;
- }
-
- // exposing the number of visits publicly (number used to compute conversions rates)
- protected $nb_visits = null;
- protected $nb_visits_converted = null;
-
- protected function setNumberOfVisits($nb_visits)
- {
- $this->nb_visits = $nb_visits;
- }
- public function getNumberOfVisits()
- {
- return $this->nb_visits;
- }
- protected function setNumberOfVisitsConverted($nb_visits_converted)
- {
- $this->nb_visits_converted = $nb_visits_converted;
- }
- public function getNumberOfVisitsConverted()
- {
- return $this->nb_visits_converted;
- }
-
-
- /**
- * Returns the idArchive we will use for the current archive
- *
- * @return int IdArchive to use when saving the current Archive
- */
- protected function loadNextIdarchive()
- {
- $table = $this->tableArchiveNumeric->getTableName();
- $dbLockName = "loadNextIdArchive.$table";
-
- $db = Zend_Registry::get('db');
- $locked = self::PREFIX_SQL_LOCK . Piwik_Common::generateUniqId();
- $date = date("Y-m-d H:i:s");
-
- if (Piwik_GetDbLock($dbLockName, $maxRetries = 30) === false)
- {
- throw new Exception("loadNextIdArchive: Cannot get named lock for table $table.");
- }
- $db->exec("INSERT INTO $table "
- ." SELECT ifnull(max(idarchive),0)+1,
- '".$locked."',
- ".(int)$this->idsite.",
- '".$date."',
- '".$date."',
+ }
+
+ /**
+ * Post processing called at the end of the main archive processing.
+ * Makes sure the new archive is marked as "successful" in the DB
+ *
+ * We also try to delete some stuff from memory but really there is still a lot...
+ */
+ protected function postCompute()
+ {
+ // delete the first done = ERROR
+ $done = $this->getDoneStringFlag();
+ Piwik_Query("DELETE FROM " . $this->tableArchiveNumeric->getTableName() . "
+ WHERE idarchive = ? AND (name = '" . $done . "' OR name LIKE '" . self::PREFIX_SQL_LOCK . "%')",
+ array($this->idArchive)
+ );
+
+ $flag = Piwik_ArchiveProcessing::DONE_OK;
+ if ($this->isArchiveTemporary()) {
+ $flag = Piwik_ArchiveProcessing::DONE_OK_TEMPORARY;
+ }
+ $this->insertNumericRecord($done, $flag);
+ }
+
+ /**
+ * Returns the name of the numeric table where the archive numeric values are stored
+ *
+ * @return string
+ */
+ public function getTableArchiveNumericName()
+ {
+ return $this->tableArchiveNumeric->getTableName();
+ }
+
+ /**
+ * Returns the name of the blob table where the archive blob values are stored
+ *
+ * @return string
+ */
+ public function getTableArchiveBlobName()
+ {
+ return $this->tableArchiveBlob->getTableName();
+ }
+
+ /**
+ * Set the period
+ *
+ * @param Piwik_Period $period
+ */
+ public function setPeriod(Piwik_Period $period)
+ {
+ $this->period = $period;
+ }
+
+ public function setSegment(Piwik_Segment $segment)
+ {
+ $this->segment = $segment;
+ }
+
+ public function getSegment()
+ {
+ return $this->segment;
+ }
+
+ /**
+ * Set the site
+ *
+ * @param Piwik_Site $site
+ */
+ public function setSite(Piwik_Site $site)
+ {
+ $this->site = $site;
+ }
+
+ public function setRequestedReport($requestedReport)
+ {
+ $this->requestedReport = $requestedReport;
+ }
+
+ protected function getRequestedReport()
+ {
+ return $this->requestedReport;
+ }
+
+ static public function getPluginBeingProcessed($requestedReport)
+ {
+ $plugin = substr($requestedReport, 0, strpos($requestedReport, '_'));
+ if (empty($plugin)
+ || !Piwik_PluginsManager::getInstance()->isPluginActivated($plugin)
+ ) {
+ $pluginStr = empty($plugin) ? '' : "($plugin)";
+ throw new Exception("Error: The report '$requestedReport' was requested but it is not available at this stage. You may also disable the related plugin $pluginStr to avoid this error.");
+ }
+ return $plugin;
+ }
+
+ /**
+ * Returns the timestamp of the first date of the period
+ *
+ * @return int
+ */
+ public function getTimestampStartDate()
+ {
+ return $this->timestampDateStart;
+ }
+
+ // exposing the number of visits publicly (number used to compute conversions rates)
+ protected $nb_visits = null;
+ protected $nb_visits_converted = null;
+
+ protected function setNumberOfVisits($nb_visits)
+ {
+ $this->nb_visits = $nb_visits;
+ }
+
+ public function getNumberOfVisits()
+ {
+ return $this->nb_visits;
+ }
+
+ protected function setNumberOfVisitsConverted($nb_visits_converted)
+ {
+ $this->nb_visits_converted = $nb_visits_converted;
+ }
+
+ public function getNumberOfVisitsConverted()
+ {
+ return $this->nb_visits_converted;
+ }
+
+
+ /**
+ * Returns the idArchive we will use for the current archive
+ *
+ * @return int IdArchive to use when saving the current Archive
+ */
+ protected function loadNextIdarchive()
+ {
+ $table = $this->tableArchiveNumeric->getTableName();
+ $dbLockName = "loadNextIdArchive.$table";
+
+ $db = Zend_Registry::get('db');
+ $locked = self::PREFIX_SQL_LOCK . Piwik_Common::generateUniqId();
+ $date = date("Y-m-d H:i:s");
+
+ if (Piwik_GetDbLock($dbLockName, $maxRetries = 30) === false) {
+ throw new Exception("loadNextIdArchive: Cannot get named lock for table $table.");
+ }
+ $db->exec("INSERT INTO $table "
+ . " SELECT ifnull(max(idarchive),0)+1,
+ '" . $locked . "',
+ " . (int)$this->idsite . ",
+ '" . $date . "',
+ '" . $date . "',
0,
- '".$date."',
+ '" . $date . "',
0 "
- ." FROM $table as tb1");
- Piwik_ReleaseDbLock($dbLockName);
+ . " FROM $table as tb1");
+ Piwik_ReleaseDbLock($dbLockName);
$id = $db->fetchOne("SELECT idarchive FROM $table WHERE name = ? LIMIT 1", $locked);
- $this->idArchive = $id;
- }
-
- /**
- * @param string $name
- * @param int|float $value
- */
- public function insertNumericRecord($name, $value)
- {
- $value = round($value, 2);
- return $this->insertRecord($name, $value);
- }
-
- /**
- * @param string $name
- * @param string|array $values
- * @return bool|array
- */
- public function insertBlobRecord($name, $values)
- {
- if(is_array($values))
- {
- $clean = array();
- foreach($values as $id => $value)
- {
- // for the parent Table we keep the name
- // for example for the Table of searchEngines we keep the name 'referer_search_engine'
- // but for the child table of 'Google' which has the ID = 9 the name would be 'referer_search_engine_9'
- $newName = $name;
- if($id != 0)
- {
- $newName = $name . '_' . $id;
- }
-
- if($this->compressBlob)
- {
- $value = $this->compress($value);
- }
- $clean[] = array($newName, $value);
- }
- return $this->insertBulkRecords($clean);
- }
-
- if($this->compressBlob)
- {
- $values = $this->compress($values);
- }
-
- $this->insertRecord($name, $values);
- return array($name => $values);
- }
-
- protected function compress($data)
- {
- return gzcompress($data);
- }
-
- protected function insertBulkRecords($records)
- {
- // Using standard plain INSERT if there is only one record to insert
- if($DEBUG_DO_NOT_USE_BULK_INSERT = false
- || count($records) == 1)
- {
- foreach($records as $record)
- {
- $this->insertRecord($record[0], $record[1]);
- }
- return ;
- }
- $bindSql = $this->getBindArray();
- $values = array();
-
- foreach($records as $record)
- {
- // don't record zero
- if(empty($record[1])) continue;
-
- $bind = $bindSql;
- $bind[] = $record[0]; // name
- $bind[] = $record[1]; // value
- $values[] = $bind;
-
- }
- if(empty($values)) return ;
-
- if(is_numeric($record[1]))
- {
- $table = $this->tableArchiveNumeric;
- }
- else
- {
- $table = $this->tableArchiveBlob;
- }
-
- Piwik::tableInsertBatch($table->getTableName(), $this->getInsertFields(), $values);
- return true;
- }
-
- protected function getBindArray()
- {
- return array( $this->idArchive,
- $this->idsite,
- $this->period->getDateStart()->toString('Y-m-d'),
- $this->period->getDateEnd()->toString('Y-m-d'),
- $this->periodId,
- date("Y-m-d H:i:s"));
- }
-
- protected function getInsertFields()
- {
- return array('idarchive', 'idsite', 'date1', 'date2', 'period', 'ts_archived', 'name', 'value');
- }
-
- /**
- * Inserts a record in the right table (either NUMERIC or BLOB)
- * @param $name
- * @param $value
- * @return
- */
- protected function insertRecord($name, $value)
- {
- // table to use to save the data
- if(is_numeric($value))
- {
- // We choose not to record records with a value of 0
- if($value == 0)
- {
- return;
- }
- $table = $this->tableArchiveNumeric;
- }
- else
- {
- $table = $this->tableArchiveBlob;
- }
-
- // duplicate idarchives are Ignored, see http://dev.piwik.org/trac/ticket/987
-
- $query = "INSERT IGNORE INTO ".$table->getTableName()."
- (". implode(", ", $this->getInsertFields()).")
+ $this->idArchive = $id;
+ }
+
+ /**
+ * @param string $name
+ * @param int|float $value
+ */
+ public function insertNumericRecord($name, $value)
+ {
+ $value = round($value, 2);
+ return $this->insertRecord($name, $value);
+ }
+
+ /**
+ * @param string $name
+ * @param string|array $values
+ * @return bool|array
+ */
+ public function insertBlobRecord($name, $values)
+ {
+ if (is_array($values)) {
+ $clean = array();
+ foreach ($values as $id => $value) {
+ // for the parent Table we keep the name
+ // for example for the Table of searchEngines we keep the name 'referer_search_engine'
+ // but for the child table of 'Google' which has the ID = 9 the name would be 'referer_search_engine_9'
+ $newName = $name;
+ if ($id != 0) {
+ $newName = $name . '_' . $id;
+ }
+
+ if ($this->compressBlob) {
+ $value = $this->compress($value);
+ }
+ $clean[] = array($newName, $value);
+ }
+ return $this->insertBulkRecords($clean);
+ }
+
+ if ($this->compressBlob) {
+ $values = $this->compress($values);
+ }
+
+ $this->insertRecord($name, $values);
+ return array($name => $values);
+ }
+
+ protected function compress($data)
+ {
+ return gzcompress($data);
+ }
+
+ protected function insertBulkRecords($records)
+ {
+ // Using standard plain INSERT if there is only one record to insert
+ if ($DEBUG_DO_NOT_USE_BULK_INSERT = false
+ || count($records) == 1
+ ) {
+ foreach ($records as $record) {
+ $this->insertRecord($record[0], $record[1]);
+ }
+ return;
+ }
+ $bindSql = $this->getBindArray();
+ $values = array();
+
+ foreach ($records as $record) {
+ // don't record zero
+ if (empty($record[1])) continue;
+
+ $bind = $bindSql;
+ $bind[] = $record[0]; // name
+ $bind[] = $record[1]; // value
+ $values[] = $bind;
+
+ }
+ if (empty($values)) return;
+
+ if (is_numeric($record[1])) {
+ $table = $this->tableArchiveNumeric;
+ } else {
+ $table = $this->tableArchiveBlob;
+ }
+
+ Piwik::tableInsertBatch($table->getTableName(), $this->getInsertFields(), $values);
+ return true;
+ }
+
+ protected function getBindArray()
+ {
+ return array($this->idArchive,
+ $this->idsite,
+ $this->period->getDateStart()->toString('Y-m-d'),
+ $this->period->getDateEnd()->toString('Y-m-d'),
+ $this->periodId,
+ date("Y-m-d H:i:s"));
+ }
+
+ protected function getInsertFields()
+ {
+ return array('idarchive', 'idsite', 'date1', 'date2', 'period', 'ts_archived', 'name', 'value');
+ }
+
+ /**
+ * Inserts a record in the right table (either NUMERIC or BLOB)
+ * @param $name
+ * @param $value
+ * @return
+ */
+ protected function insertRecord($name, $value)
+ {
+ // table to use to save the data
+ if (is_numeric($value)) {
+ // We choose not to record records with a value of 0
+ if ($value == 0) {
+ return;
+ }
+ $table = $this->tableArchiveNumeric;
+ } else {
+ $table = $this->tableArchiveBlob;
+ }
+
+ // duplicate idarchives are Ignored, see http://dev.piwik.org/trac/ticket/987
+
+ $query = "INSERT IGNORE INTO " . $table->getTableName() . "
+ (" . implode(", ", $this->getInsertFields()) . ")
VALUES (?,?,?,?,?,?,?,?)";
- $bindSql = $this->getBindArray();
- $bindSql[] = $name;
- $bindSql[] = $value;
- Piwik_Query($query, $bindSql);
- }
-
- /**
- * Returns the idArchive if the archive is available in the database.
- * Returns false if the archive needs to be computed.
- *
- * An archive is available if
- * - for today, the archive was computed less than minDatetimeArchiveProcessedUTC seconds ago
- * - for any other day, if the archive was computed once this day was finished
- * - for other periods, if the archive was computed once the period was finished
- *
- * @return int|false
- */
- protected function isArchived()
- {
- $bindSQL = array( $this->idsite,
- $this->period->getDateStart()->toString('Y-m-d'),
- $this->period->getDateEnd()->toString('Y-m-d'),
- $this->periodId,
- );
-
- $timeStampWhere = '';
-
- if($this->minDatetimeArchiveProcessedUTC)
- {
- $timeStampWhere = " AND ts_archived >= ? ";
- $bindSQL[] = Piwik_Date::factory($this->minDatetimeArchiveProcessedUTC)->getDatetime();
- }
-
- // When a Segment is specified, we try and only process the requested report in the archive
- // As a limitation, we don't know all the time which plugin should process which report
- // There is a catch all flag 'all' appended to archives containing all reports already
- // We look for this 'done.ABCDEFG.all', or for an archive that contains only our plugin data 'done.ABDCDEFG.Referers'
- $done = $this->getDoneStringFlag();
- $doneAllPluginsProcessed = $this->getDoneStringFlag($flagArchiveAsAllPlugins = true);
-
- $sqlSegmentsFindArchiveAllPlugins = '';
-
- if($done != $doneAllPluginsProcessed)
- {
- $sqlSegmentsFindArchiveAllPlugins = "OR (name = '".$doneAllPluginsProcessed."' AND value = ".Piwik_ArchiveProcessing::DONE_OK.")
- OR (name = '".$doneAllPluginsProcessed."' AND value = ".Piwik_ArchiveProcessing::DONE_OK_TEMPORARY.")";
- }
- $sqlQuery = " SELECT idarchive, value, name, date1 as startDate
- FROM ".$this->tableArchiveNumeric->getTableName()."
+ $bindSql = $this->getBindArray();
+ $bindSql[] = $name;
+ $bindSql[] = $value;
+ Piwik_Query($query, $bindSql);
+ }
+
+ /**
+ * Returns the idArchive if the archive is available in the database.
+ * Returns false if the archive needs to be computed.
+ *
+ * An archive is available if
+ * - for today, the archive was computed less than minDatetimeArchiveProcessedUTC seconds ago
+ * - for any other day, if the archive was computed once this day was finished
+ * - for other periods, if the archive was computed once the period was finished
+ *
+ * @return int|false
+ */
+ protected function isArchived()
+ {
+ $bindSQL = array($this->idsite,
+ $this->period->getDateStart()->toString('Y-m-d'),
+ $this->period->getDateEnd()->toString('Y-m-d'),
+ $this->periodId,
+ );
+
+ $timeStampWhere = '';
+
+ if ($this->minDatetimeArchiveProcessedUTC) {
+ $timeStampWhere = " AND ts_archived >= ? ";
+ $bindSQL[] = Piwik_Date::factory($this->minDatetimeArchiveProcessedUTC)->getDatetime();
+ }
+
+ // When a Segment is specified, we try and only process the requested report in the archive
+ // As a limitation, we don't know all the time which plugin should process which report
+ // There is a catch all flag 'all' appended to archives containing all reports already
+ // We look for this 'done.ABCDEFG.all', or for an archive that contains only our plugin data 'done.ABDCDEFG.Referers'
+ $done = $this->getDoneStringFlag();
+ $doneAllPluginsProcessed = $this->getDoneStringFlag($flagArchiveAsAllPlugins = true);
+
+ $sqlSegmentsFindArchiveAllPlugins = '';
+
+ if ($done != $doneAllPluginsProcessed) {
+ $sqlSegmentsFindArchiveAllPlugins = "OR (name = '" . $doneAllPluginsProcessed . "' AND value = " . Piwik_ArchiveProcessing::DONE_OK . ")
+ OR (name = '" . $doneAllPluginsProcessed . "' AND value = " . Piwik_ArchiveProcessing::DONE_OK_TEMPORARY . ")";
+ }
+ $sqlQuery = " SELECT idarchive, value, name, date1 as startDate
+ FROM " . $this->tableArchiveNumeric->getTableName() . "
WHERE idsite = ?
AND date1 = ?
AND date2 = ?
AND period = ?
- AND ( (name = '".$done."' AND value = ".Piwik_ArchiveProcessing::DONE_OK.")
- OR (name = '".$done."' AND value = ".Piwik_ArchiveProcessing::DONE_OK_TEMPORARY.")
+ AND ( (name = '" . $done . "' AND value = " . Piwik_ArchiveProcessing::DONE_OK . ")
+ OR (name = '" . $done . "' AND value = " . Piwik_ArchiveProcessing::DONE_OK_TEMPORARY . ")
$sqlSegmentsFindArchiveAllPlugins
OR name = 'nb_visits')
$timeStampWhere
ORDER BY idarchive DESC";
- $results = Piwik_FetchAll($sqlQuery, $bindSQL );
- if(empty($results))
- {
- return false;
- }
-
- $idarchive = false;
- // we look for the more recent idarchive
- foreach($results as $result)
- {
- if($result['name'] == $done
- || $result['name'] == $doneAllPluginsProcessed)
- {
- $idarchive = $result['idarchive'];
- $this->timestampDateStart = Piwik_Date::factory($result['startDate'])->getTimestamp();
- break;
- }
- }
-
- // case when we have a nb_visits entry in the archive, but the process is not finished yet or failed to finish
- // therefore we don't have the done=OK
- if($idarchive === false)
- {
- return false;
- }
-
- if($this->getPluginBeingProcessed($this->getRequestedReport()) == 'VisitsSummary')
- {
- $this->isThereSomeVisits = false;
- }
-
- // we look for the nb_visits result for this most recent archive
- foreach($results as $result)
- {
- if($result['name'] == 'nb_visits'
- && $result['idarchive'] == $idarchive)
- {
- $this->isThereSomeVisits = ($result['value'] > 0);
- $this->setNumberOfVisits($result['value']);
- break;
- }
- }
- return $idarchive;
- }
-
- /**
- * Returns true if, for some reasons, triggering the archiving is disabled.
- * Note that when a segment is passed to the function, archiving will always occur
- * (since segments are by default not pre-processed)
- *
- * @return bool
- */
- public function isArchivingDisabled()
- {
- return self::isArchivingDisabledFor($this->getSegment(), $this->period);
- }
-
- public static function isArchivingDisabledFor($segment, $period)
- {
- if($period->getLabel() == 'range') {
+ $results = Piwik_FetchAll($sqlQuery, $bindSQL);
+ if (empty($results)) {
+ return false;
+ }
+
+ $idarchive = false;
+ // we look for the more recent idarchive
+ foreach ($results as $result) {
+ if ($result['name'] == $done
+ || $result['name'] == $doneAllPluginsProcessed
+ ) {
+ $idarchive = $result['idarchive'];
+ $this->timestampDateStart = Piwik_Date::factory($result['startDate'])->getTimestamp();
+ break;
+ }
+ }
+
+ // case when we have a nb_visits entry in the archive, but the process is not finished yet or failed to finish
+ // therefore we don't have the done=OK
+ if ($idarchive === false) {
+ return false;
+ }
+
+ if ($this->getPluginBeingProcessed($this->getRequestedReport()) == 'VisitsSummary') {
+ $this->isThereSomeVisits = false;
+ }
+
+ // we look for the nb_visits result for this most recent archive
+ foreach ($results as $result) {
+ if ($result['name'] == 'nb_visits'
+ && $result['idarchive'] == $idarchive
+ ) {
+ $this->isThereSomeVisits = ($result['value'] > 0);
+ $this->setNumberOfVisits($result['value']);
+ break;
+ }
+ }
+ return $idarchive;
+ }
+
+ /**
+ * Returns true if, for some reasons, triggering the archiving is disabled.
+ * Note that when a segment is passed to the function, archiving will always occur
+ * (since segments are by default not pre-processed)
+ *
+ * @return bool
+ */
+ public function isArchivingDisabled()
+ {
+ return self::isArchivingDisabledFor($this->getSegment(), $this->period);
+ }
+
+ public static function isArchivingDisabledFor($segment, $period)
+ {
+ if ($period->getLabel() == 'range') {
return false;
}
$processOneReportOnly = !self::shouldProcessReportsAllPluginsFor($segment, $period);
$isArchivingDisabled = !self::isRequestAuthorizedToArchive();
- if($processOneReportOnly)
- {
+ if ($processOneReportOnly) {
// When there is a segment, archiving is not necessary allowed
// If browser archiving is allowed, then archiving is enabled
// if browser archiving is not allowed, then archiving is disabled
- if(!$segment->isEmpty()
+ if (!$segment->isEmpty()
&& $isArchivingDisabled
&& Piwik_Config::getInstance()->General['browser_archiving_disabled_enforce']
- )
- {
+ ) {
Piwik::log("Archiving is disabled because of config setting browser_archiving_disabled_enforce=1");
return true;
}
return false;
}
- return $isArchivingDisabled;
- }
-
- protected static function isRequestAuthorizedToArchive()
- {
- return !self::$forceDisableArchiving &&
- (self::isBrowserTriggerArchivingEnabled()
- || Piwik_Common::isPhpCliMode()
- || (Piwik::isUserIsSuperUser()
- && Piwik_Common::isArchivePhpTriggered()))
- ;
- }
-
- /**
- * Returns true when
- * - there is no segment and period is not range
- * - there is a segment that is part of the preprocessed [Segments] list
- * @param Piwik_Segment $segment
- * @param Piwik_Period $period
- * @return bool
- */
- protected function shouldProcessReportsAllPlugins($segment, $period)
- {
- return self::shouldProcessReportsAllPluginsFor($segment, $period);
- }
-
- /**
- * @param Piwik_Segment $segment
- * @param Piwik_Period $period
- * @return bool
- */
- protected static function shouldProcessReportsAllPluginsFor($segment, $period)
- {
- if($segment->isEmpty() && $period->getLabel() != 'range')
- {
- return true;
- }
-
- $segmentsToProcess = Piwik::getKnownSegmentsToArchive();
- if(!empty($segmentsToProcess))
- {
- // If the requested segment is one of the segments to pre-process
- // we ensure that any call to the API will trigger archiving of all reports for this segment
- $segment = $segment->getString();
- if(in_array($segment, $segmentsToProcess))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * When a segment is set, we shall only process the requested report (no more).
- * The requested data set will return a lot faster if we only process these reports rather than all plugins.
- * Similarly, when a period=range is requested, we shall only process the requested report for the range itself.
- *
- * @param string $pluginName
- * @return bool
- */
- public function shouldProcessReportsForPlugin($pluginName)
- {
- if($this->shouldProcessReportsAllPlugins($this->getSegment(), $this->period))
- {
- return true;
- }
-
- // If any other segment, only process if the requested report belong to this plugin
- // or process all plugins if the requested report plugin couldn't be guessed
- $pluginBeingProcessed = self::getPluginBeingProcessed($this->getRequestedReport());
- return $pluginBeingProcessed == $pluginName
- || !Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginBeingProcessed)
- ;
- }
-
+ return $isArchivingDisabled;
+ }
+
+ protected static function isRequestAuthorizedToArchive()
+ {
+ return !self::$forceDisableArchiving &&
+ (self::isBrowserTriggerArchivingEnabled()
+ || Piwik_Common::isPhpCliMode()
+ || (Piwik::isUserIsSuperUser()
+ && Piwik_Common::isArchivePhpTriggered()));
+ }
+
+ /**
+ * Returns true when
+ * - there is no segment and period is not range
+ * - there is a segment that is part of the preprocessed [Segments] list
+ * @param Piwik_Segment $segment
+ * @param Piwik_Period $period
+ * @return bool
+ */
+ protected function shouldProcessReportsAllPlugins($segment, $period)
+ {
+ return self::shouldProcessReportsAllPluginsFor($segment, $period);
+ }
+
+ /**
+ * @param Piwik_Segment $segment
+ * @param Piwik_Period $period
+ * @return bool
+ */
+ protected static function shouldProcessReportsAllPluginsFor($segment, $period)
+ {
+ if ($segment->isEmpty() && $period->getLabel() != 'range') {
+ return true;
+ }
+
+ $segmentsToProcess = Piwik::getKnownSegmentsToArchive();
+ if (!empty($segmentsToProcess)) {
+ // If the requested segment is one of the segments to pre-process
+ // we ensure that any call to the API will trigger archiving of all reports for this segment
+ $segment = $segment->getString();
+ if (in_array($segment, $segmentsToProcess)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * When a segment is set, we shall only process the requested report (no more).
+ * The requested data set will return a lot faster if we only process these reports rather than all plugins.
+ * Similarly, when a period=range is requested, we shall only process the requested report for the range itself.
+ *
+ * @param string $pluginName
+ * @return bool
+ */
+ public function shouldProcessReportsForPlugin($pluginName)
+ {
+ if ($this->shouldProcessReportsAllPlugins($this->getSegment(), $this->period)) {
+ return true;
+ }
+
+ // If any other segment, only process if the requested report belong to this plugin
+ // or process all plugins if the requested report plugin couldn't be guessed
+ $pluginBeingProcessed = self::getPluginBeingProcessed($this->getRequestedReport());
+ return $pluginBeingProcessed == $pluginName
+ || !Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginBeingProcessed);
+ }
+
}