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:
-rw-r--r--core/Archive.php51
-rw-r--r--core/Archive/Array/IndexedByDate.php22
-rw-r--r--core/Archive/Array/IndexedBySite.php28
-rw-r--r--core/Archive/Single.php28
-rw-r--r--core/ArchiveProcessing.php115
-rw-r--r--core/ArchiveProcessing/Day.php241
-rw-r--r--core/ArchiveProcessing/Period.php19
-rw-r--r--core/Segment.php127
-rw-r--r--core/SegmentExpression.php228
-rw-r--r--core/Site.php2
-rw-r--r--core/Tracker/Action.php13
-rw-r--r--lang/en.php11
-rw-r--r--plugins/API/API.php70
-rw-r--r--plugins/Actions/API.php40
-rw-r--r--plugins/Actions/Actions.php110
-rw-r--r--plugins/CustomVariables/API.php12
-rw-r--r--plugins/CustomVariables/CustomVariables.php48
-rw-r--r--plugins/Goals/API.php20
-rw-r--r--plugins/Goals/Controller.php4
-rw-r--r--plugins/Goals/Goals.php9
-rw-r--r--plugins/PDFReports/API.php2
-rw-r--r--plugins/Provider/API.php4
-rw-r--r--plugins/Provider/Provider.php18
-rw-r--r--plugins/Proxy/Controller.php8
-rw-r--r--plugins/Referers/API.php104
-rw-r--r--plugins/Referers/Controller.php87
-rw-r--r--plugins/Referers/Referers.php40
-rw-r--r--plugins/UserCountry/API.php16
-rw-r--r--plugins/UserCountry/UserCountry.php54
-rw-r--r--plugins/UserSettings/API.php38
-rw-r--r--plugins/UserSettings/UserSettings.php101
-rw-r--r--plugins/VisitFrequency/VisitFrequency.php5
-rw-r--r--plugins/VisitTime/API.php12
-rw-r--r--plugins/VisitTime/VisitTime.php31
-rw-r--r--plugins/VisitorInterest/API.php12
-rw-r--r--plugins/VisitorInterest/VisitorInterest.php4
-rw-r--r--plugins/VisitsSummary/API.php40
-rw-r--r--tests/core/Database.test.php1
-rw-r--r--tests/core/Segment.test.php78
-rw-r--r--tests/core/SegmentExpression.test.php89
-rw-r--r--tests/integration/Integration.php5
-rw-r--r--tests/integration/Main.test.php9
-rw-r--r--tests/integration/expected/test_OneVisitorTwoVisits__Actions.getPageUrls_day.xml2
-rw-r--r--tests/integration/expected/test_OneVisitorTwoVisits__Referers.getKeywordsForPageUrl_day.xml4
-rw-r--r--tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Actions.getPageUrls_day.xml2
-rw-r--r--tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Referers.getKeywordsForPageUrl_day.xml4
-rw-r--r--tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_day.xml5
-rw-r--r--tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_month.xml5
-rw-r--r--tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_day.xml14
-rw-r--r--tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_month.xml24
-rw-r--r--tests/integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml200
-rw-r--r--tests/integration/expected/test_noVisit__Referers.getKeywordsForPageUrl_day.xml2
52 files changed, 1873 insertions, 345 deletions
diff --git a/core/Archive.php b/core/Archive.php
index ebf4160197..75f93364ac 100644
--- a/core/Archive.php
+++ b/core/Archive.php
@@ -131,12 +131,10 @@ abstract class Piwik_Archive
protected $site = null;
/**
- * Stores the already built archives.
- * Act as a big caching array
- *
- * @var array of Piwik_Archive
+ * Segment applied to the visits set
+ * @var Piwik_Segment
*/
- static protected $alreadyBuilt = array();
+ protected $segment = false;
/**
* Builds an Archive object or returns the same archive if previously built.
@@ -144,10 +142,11 @@ abstract class Piwik_Archive
* @param string|int idSite integer, or comma separated list of integer
* @param string|Piwik_Date $date 'YYYY-MM-DD' or magic keywords 'today' @see Piwik_Date::factory()
* @param string $period 'week' 'day' etc.
+ * @param string Segment definition - defaults to false for Backward Compatibility
*
* @return Piwik_Archive
*/
- static public function build($idSite, $period, $strDate )
+ static public function build($idSite, $period, $strDate, $segment = false )
{
if($idSite === 'all')
{
@@ -158,11 +157,15 @@ abstract class Piwik_Archive
$sites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
}
+ // @TODO read setting enable segmentation
+ $segment = Piwik_Common::unsanitizeInputValue($segment);
+ $segment = new Piwik_Segment($segment, $idSite);
+
// idSite=1,3 or idSite=all
if( count($sites) > 1
|| $idSite === 'all' )
{
- $archive = new Piwik_Archive_Array_IndexedBySite($sites, $period, $strDate);
+ $archive = new Piwik_Archive_Array_IndexedBySite($sites, $period, $strDate, $segment);
}
// if a period date string is detected: either 'last30', 'previous10' or 'YYYY-MM-DD,YYYY-MM-DD'
elseif(is_string($strDate)
@@ -173,7 +176,7 @@ abstract class Piwik_Archive
)
{
$oSite = new Piwik_Site($idSite);
- $archive = new Piwik_Archive_Array_IndexedByDate($oSite, $period, $strDate);
+ $archive = new Piwik_Archive_Array_IndexedByDate($oSite, $period, $strDate, $segment);
}
// case we request a single archive
else
@@ -198,25 +201,13 @@ abstract class Piwik_Archive
}
$date = $oDate->toString();
- if(isset(self::$alreadyBuilt[$idSite][$date][$period]))
- {
- return self::$alreadyBuilt[$idSite][$date][$period];
- }
-
$oPeriod = Piwik_Period::factory($period, $oDate);
$archive = new Piwik_Archive_Single();
$archive->setPeriod($oPeriod);
$archive->setSite($oSite);
- $archiveJustProcessed = $archive->prepareArchive();
-
- //we don't cache the archives just processed, the datatable were freed from memory
- if(!$archiveJustProcessed)
- {
- self::$alreadyBuilt[$idSite][$date][$period] = $archive;
- }
+ $archive->setSegment($segment);
}
-
return $archive;
}
@@ -279,10 +270,10 @@ abstract class Piwik_Archive
* Optionally loads the table recursively,
* or optionally fetches a given subtable with $idSubtable
*/
- static public function getDataTableFromArchive($name, $idSite, $period, $date, $expanded, $idSubtable = null )
+ static public function getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $idSubtable = null )
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
if($idSubtable === false)
{
$idSubtable = null;
@@ -302,6 +293,16 @@ abstract class Piwik_Archive
return $dataTable;
}
+ protected function getSegment()
+ {
+ return $this->segment;
+ }
+
+ public function setSegment(Piwik_Segment $segment)
+ {
+ $this->segment = $segment;
+ }
+
/**
* Sets the site
*
@@ -332,8 +333,4 @@ abstract class Piwik_Archive
return $this->site->getId();
}
- static public function clearCache()
- {
- self::$alreadyBuilt = array();
- }
}
diff --git a/core/Archive/Array/IndexedByDate.php b/core/Archive/Array/IndexedByDate.php
index 319e3382d5..b07faced5a 100644
--- a/core/Archive/Array/IndexedByDate.php
+++ b/core/Archive/Array/IndexedByDate.php
@@ -23,18 +23,16 @@ class Piwik_Archive_Array_IndexedByDate extends Piwik_Archive_Array
* @param string $strPeriod eg. 'day' 'week' etc.
* @param string $strDate A date range, eg. 'last10', 'previous5' or 'YYYY-MM-DD,YYYY-MM-DD'
*/
- function __construct(Piwik_Site $oSite, $strPeriod, $strDate)
+ function __construct(Piwik_Site $oSite, $strPeriod, $strDate, Piwik_Segment $segment)
{
$rangePeriod = new Piwik_Period_Range($strPeriod, $strDate, $oSite->getTimezone());
foreach($rangePeriod->getSubperiods() as $subPeriod)
{
$startDate = $subPeriod->getDateStart();
- $archive = Piwik_Archive::build($oSite->getId(), $strPeriod, $startDate );
- $archive->prepareArchive();
- $timestamp = $archive->getTimestampStartDate();
- $this->archives[$timestamp] = $archive;
+ $archive = Piwik_Archive::build($oSite->getId(), $strPeriod, $startDate, $segment->getString() );
+ $archive->setSegment($segment);
+ $this->archives[] = $archive;
}
- ksort( $this->archives );
}
protected function getIndexName()
@@ -79,6 +77,8 @@ class Piwik_Archive_Array_IndexedByDate extends Piwik_Archive_Array
$queries = array();
foreach($this->archives as $archive)
{
+ $archive->setRequestedReport( is_string($fields) ? $fields : current($fields) );
+ $archive->prepareArchive();
if(!$archive->isThereSomeVisits)
{
continue;
@@ -120,11 +120,13 @@ class Piwik_Archive_Array_IndexedByDate extends Piwik_Archive_Array
$contentArray = array();
// we add empty tables so that every requested date has an entry, even if there is nothing
// example: <result date="2007-01-01" />
- foreach($this->archives as $timestamp => $archive)
+ $archiveByTimestamp = array();
+ foreach($this->archives as $archive)
{
- $strDate = $this->archives[$timestamp]->getPrettyDate();
+ $timestamp = $archive->getTimestampStartDate();
+ $archiveByTimestamp[$timestamp] = $archive;
$contentArray[$timestamp]['table'] = new Piwik_DataTable_Simple();
- $contentArray[$timestamp]['prettyDate'] = $strDate;
+ $contentArray[$timestamp]['prettyDate'] = $archive->getPrettyDate();
}
foreach($arrayValues as $timestamp => $aNameValues)
@@ -137,7 +139,7 @@ class Piwik_Archive_Array_IndexedByDate extends Piwik_Archive_Array
foreach($contentArray as $timestamp => $aData)
{
$tableArray->addTable($aData['table'], $aData['prettyDate']);
- $this->loadMetadata($tableArray, $this->archives[$timestamp]);
+ $this->loadMetadata($tableArray, $archiveByTimestamp[$timestamp]);
}
return $tableArray;
}
diff --git a/core/Archive/Array/IndexedBySite.php b/core/Archive/Array/IndexedBySite.php
index 0b2e76e129..1be0dd0771 100644
--- a/core/Archive/Array/IndexedBySite.php
+++ b/core/Archive/Array/IndexedBySite.php
@@ -21,13 +21,13 @@ class Piwik_Archive_Array_IndexedBySite extends Piwik_Archive_Array
* @param string $strPeriod eg. 'day' 'week' etc.
* @param string $strDate A date range, eg. 'last10', 'previous5' or 'YYYY-MM-DD,YYYY-MM-DD'
*/
- function __construct($sites, $strPeriod, $strDate)
+ function __construct($sites, $strPeriod, $strDate, Piwik_Segment $segment)
{
foreach($sites as $idSite)
{
- $archive = Piwik_Archive::build($idSite, $strPeriod, $strDate );
+ $archive = Piwik_Archive::build($idSite, $strPeriod, $strDate, $segment->getString() );
$archive->setSite(new Piwik_Site($idSite));
- $archive->prepareArchive();
+ $archive->setSegment($segment);
$this->archives[$idSite] = $archive;
}
ksort( $this->archives );
@@ -79,6 +79,12 @@ class Piwik_Archive_Array_IndexedBySite extends Piwik_Archive_Array
private function getValues($fields)
{
+ foreach($this->archives as $archive)
+ {
+ $archive->setRequestedReport( is_string($fields) ? $fields : current($fields) );
+ $archive->prepareArchive();
+ }
+
$arrayValues = array();
foreach($this->loadValuesFromDB($fields) as $value)
{
@@ -90,9 +96,14 @@ class Piwik_Archive_Array_IndexedBySite extends Piwik_Archive_Array
private function loadValuesFromDB($fields)
{
$inNames = $this->getSqlStringFieldsArray($fields);
+ $archiveIds = $this->getArchiveIds();
+ if(empty($archiveIds))
+ {
+ return array();
+ }
$sql = "SELECT value, name, idarchive, idsite
FROM {$this->getNumericTableName()}
- WHERE idarchive IN ( {$this->getArchiveIds()} )
+ WHERE idarchive IN ( $archiveIds )
AND name IN ( $inNames )";
return Piwik_FetchAll($sql, $fields);
}
@@ -105,13 +116,20 @@ class Piwik_Archive_Array_IndexedBySite extends Piwik_Archive_Array
private function getArchiveIds()
{
+ $archiveIds = array();
foreach($this->archives as $archive)
{
+ if( !$archive->isThereSomeVisits )
+ {
+ continue;
+ }
+
+ $archiveIds[] = $archive->getIdArchive();
+
if( $this->getNumericTableName() != $archive->archiveProcessing->getTableArchiveNumericName())
{
throw new Exception("Piwik_Archive_Array_IndexedBySite::getDataTableFromNumeric() algorithm won't work if data is stored in different tables");
}
- $archiveIds[] = $archive->getIdArchive();
}
return implode(', ', array_filter($archiveIds));
}
diff --git a/core/Archive/Single.php b/core/Archive/Single.php
index 0f4cf69fce..be7b42867a 100644
--- a/core/Archive/Single.php
+++ b/core/Archive/Single.php
@@ -177,6 +177,8 @@ class Piwik_Archive_Single extends Piwik_Archive
$archiveProcessing = Piwik_ArchiveProcessing::factory($periodLabel);
$archiveProcessing->setSite($this->site);
$archiveProcessing->setPeriod($this->period);
+ $archiveProcessing->setSegment($this->segment);
+ $archiveProcessing->setRequestedReport( $this->getRequestedReport() );
$idArchive = $archiveProcessing->loadArchive();
if(empty($idArchive))
{
@@ -196,13 +198,16 @@ class Piwik_Archive_Single extends Piwik_Archive
{
Piwik::log("$logMessage archive already processed [id = $idArchive]...");
}
+ $this->archiveProcessing = $archiveProcessing;
$this->isThereSomeVisits = $archiveProcessing->isThereSomeVisits;
$this->idArchive = $idArchive;
- $this->archiveProcessing = $archiveProcessing;
}
return $archiveJustProcessed;
}
+
+ protected $isArchivePrepared = false;
+
/**
* Returns a value from the current archive with the name = $name
* Method used by getNumeric or getBlob
@@ -213,6 +218,14 @@ class Piwik_Archive_Single extends Piwik_Archive
*/
protected function get( $name, $typeValue = 'numeric' )
{
+ $this->setRequestedReport($name);
+
+ if(!$this->isArchivePrepared)
+ {
+ $archiveJustProcessed = $this->prepareArchive();
+ $this->isArchivePrepared = true;
+ }
+
// values previously "get" and now cached
if($typeValue == 'numeric'
&& $this->cacheEnabledForNumeric
@@ -447,6 +460,8 @@ class Piwik_Archive_Single extends Piwik_Archive
$name .= "_$idSubTable";
}
+ $this->setRequestedReport($name);
+
$data = $this->get($name, 'blob');
$table = new Piwik_DataTable();
@@ -467,6 +482,17 @@ class Piwik_Archive_Single extends Piwik_Archive
return $table;
}
+ public function setRequestedReport($requestedReport )
+ {
+ $this->requestedReport = $requestedReport;
+ }
+
+ protected function getRequestedReport()
+ {
+ if(!isset($this->requestedReport)) { debug_print_backtrace();exit; }
+ return $this->requestedReport;
+ }
+
/**
* Returns a DataTable that has the name '$name' from the current Archive.
* Also loads in memory all subDataTable for this DataTable.
diff --git a/core/ArchiveProcessing.php b/core/ArchiveProcessing.php
index a6cae8288a..7360281cc6 100644
--- a/core/ArchiveProcessing.php
+++ b/core/ArchiveProcessing.php
@@ -149,6 +149,11 @@ abstract class Piwik_ArchiveProcessing
public $site = null;
/**
+ * @var Piwik_Segment
+ */
+ protected $segment = null;
+
+ /**
* Current time.
* This value is cached.
*
@@ -210,7 +215,7 @@ abstract class Piwik_ArchiveProcessing
* @param string $name day|week|month|year
* @return Piwik_ArchiveProcessing Piwik_ArchiveProcessing_Day|Piwik_ArchiveProcessing_Period
*/
- static function factory($name )
+ static function factory($name)
{
switch($name)
{
@@ -407,16 +412,59 @@ abstract class Piwik_ArchiveProcessing
*/
abstract protected function compute();
+ protected function getDoneStringFlag($flagArchiveAsAllPlugins = false)
+ {
+ $segment = $this->getSegment()->getHash();
+ if(!empty($segment))
+ {
+ $pluginProcessed = $this->getPluginBeingProcessed();
+ if(!Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginProcessed)
+ || $flagArchiveAsAllPlugins
+ )
+ {
+ $pluginProcessed = 'all';
+ }
+ $segment .= '.'.$pluginProcessed;
+ }
+ return 'done' . $segment;
+ }
+
+ /**
+ * When a segment is set, we shall only process the requested report (no more)
+ *
+ * The reasonning is that at the current time, Segmentation being only available via API,
+ * users will only request one or few reports, not all of them. The requested data sets
+ * will return a lot faster if we only process these reports rather than all plugins.
+ *
+ * @param string $pluginName
+ * @return bool
+ */
+ public function shouldProcessReportsForPlugin($pluginName)
+ {
+ // No segment: process reports for all plugins
+ if($this->getSegment()->isEmpty())
+ {
+ return true;
+ }
+ // If 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 = $this->getPluginBeingProcessed();
+ return $pluginBeingProcessed == $pluginName
+ || !Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginBeingProcessed)
+ ;
+ }
+
/**
* Init the object before launching the real archive processing
*/
protected function initCompute()
{
$this->loadNextIdarchive();
- $this->insertNumericRecord('done', Piwik_ArchiveProcessing::DONE_ERROR);
+ $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');
+ $this->logTable = Piwik_Common::prefixTable('log_visit');
$temporary = 'definitive archive';
if($this->isArchiveTemporary())
@@ -425,6 +473,7 @@ abstract class Piwik_ArchiveProcessing
}
Piwik::log("Processing archive '" . $this->period->getLabel() . "', "
."idsite = ". $this->idsite." ($temporary) - "
+ ."segment = ". $this->getSegment()->getString()
."UTC datetime [".$this->startDatetimeUTC." -> ".$this->endDatetimeUTC." ]...");
}
@@ -437,8 +486,9 @@ abstract class Piwik_ArchiveProcessing
protected function postCompute()
{
// delete the first done = ERROR
+ $done = $this->getDoneStringFlag();
Piwik_Query("DELETE FROM ".$this->tableArchiveNumeric->getTableName()."
- WHERE idarchive = ? AND name = 'done'",
+ WHERE idarchive = ? AND name = '".$done."'",
array($this->idArchive)
);
@@ -447,9 +497,9 @@ abstract class Piwik_ArchiveProcessing
{
$flag = Piwik_ArchiveProcessing::DONE_OK_TEMPORARY;
}
- $this->insertNumericRecord('done', $flag);
+ $this->insertNumericRecord($done, $flag);
- Piwik_DataTable_Manager::getInstance()->deleteAll();
+// Piwik_DataTable_Manager::getInstance()->deleteAll();
}
/**
@@ -482,6 +532,15 @@ abstract class Piwik_ArchiveProcessing
$this->period = $period;
}
+ public function setSegment( Piwik_Segment $segment)
+ {
+ $this->segment = $segment;
+ }
+
+ public function getSegment()
+ {
+ return $this->segment;
+ }
/**
* Set the site
*
@@ -492,6 +551,21 @@ abstract class Piwik_ArchiveProcessing
$this->site = $site;
}
+ public function setRequestedReport($requestedReport)
+ {
+ $this->requestedReport = $requestedReport;
+ }
+
+ protected function getRequestedReport()
+ {
+ return $this->requestedReport;
+ }
+
+ protected function getPluginBeingProcessed()
+ {
+ return substr($this->requestedReport, 0, strpos($this->requestedReport, '_'));
+ }
+
/**
* Returns the timestamp of the first date of the period
*
@@ -592,7 +666,6 @@ abstract class Piwik_ArchiveProcessing
*/
protected function insertRecord($record)
{
-
// table to use to save the data
if(is_numeric($record->value))
{
@@ -607,10 +680,11 @@ abstract class Piwik_ArchiveProcessing
{
$table = $this->tableArchiveBlob;
}
-
+
// ignore duplicate idarchive
// @see http://dev.piwik.org/trac/ticket/987
- $query = "INSERT IGNORE INTO ".$table->getTableName()." (idarchive, idsite, date1, date2, period, ts_archived, name, value)
+ $query = "INSERT IGNORE INTO ".$table->getTableName()."
+ (idarchive, idsite, date1, date2, period, ts_archived, name, value)
VALUES (?,?,?,?,?,?,?,?)";
$bindSql = array( $this->idArchive,
$this->idsite,
@@ -650,15 +724,29 @@ abstract class Piwik_ArchiveProcessing
$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 ts_archived DESC";
@@ -672,7 +760,8 @@ abstract class Piwik_ArchiveProcessing
// we look for the more recent idarchive
foreach($results as $result)
{
- if($result['name'] == 'done')
+ if($result['name'] == $done
+ || $result['name'] == $doneAllPluginsProcessed)
{
$idarchive = $result['idarchive'];
$this->timestampDateStart = Piwik_Date::factory($result['startDate'])->getTimestamp();
@@ -699,7 +788,7 @@ abstract class Piwik_ArchiveProcessing
}
return $idarchive;
}
-
+
/**
* Returns true if, for some reasons, triggering the archiving is disabled.
*
diff --git a/core/ArchiveProcessing/Day.php b/core/ArchiveProcessing/Day.php
index 8b28feb63c..2a57e7810f 100644
--- a/core/ArchiveProcessing/Day.php
+++ b/core/ArchiveProcessing/Day.php
@@ -36,6 +36,12 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
*/
protected function compute()
{
+ // Handling Custom Segment
+ $segmentSql = $this->getSegment()->getSql();
+ $sqlSegmentBind = $segmentSql['bind'];
+ $sqlSegment = $segmentSql['sql'];
+ if(!empty($sqlSegment)) $sqlSegment = ' AND '.$sqlSegment;
+
$query = "SELECT count(distinct idvisitor) as nb_uniq_visitors,
count(*) as nb_visits,
sum(visit_total_actions) as nb_actions,
@@ -47,8 +53,11 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
AND idsite = ?
+ $sqlSegment
ORDER BY NULL";
- $row = $this->db->fetchRow($query, array($this->getStartDatetimeUTC(), $this->getEndDatetimeUTC(), $this->idsite ) );
+ $bind = array_merge(array($this->getStartDatetimeUTC(), $this->getEndDatetimeUTC(), $this->idsite )
+ , $sqlSegmentBind);
+ $row = $this->db->fetchRow($query, $bind );
if($row === false || $row === null || $row['nb_visits'] == 0)
{
return;
@@ -85,12 +94,21 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
*/
public function getSimpleDataTableFromSelect($select, $labelCount)
{
+ // Handling Custom Segment
+ $segmentSql = $this->getSegment()->getSql();
+ $sqlSegmentBind = $segmentSql['bind'];
+ $sqlSegment = $segmentSql['sql'];
+ if(!empty($sqlSegment)) $sqlSegment = ' AND '.$sqlSegment;
+
$query = "SELECT $select
FROM ".Piwik_Common::prefixTable('log_visit')."
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
- AND idsite = ?";
- $data = $this->db->fetchRow($query, array( $this->getStartDatetimeUTC(), $this->getEndDatetimeUTC(), $this->idsite ));
+ AND idsite = ?
+ $sqlSegment";
+ $bind = array_merge(array( $this->getStartDatetimeUTC(), $this->getEndDatetimeUTC(), $this->idsite ),
+ $sqlSegmentBind);
+ $data = $this->db->fetchRow($query, $bind);
foreach($data as $label => &$count)
{
@@ -100,6 +118,147 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
$table->addRowsFromArrayWithIndexLabel($data);
return $table;
}
+
+ /**
+ * @param $label mixed Can be a string, eg. "referer_name", will be aliased as 'label' in the returned rows
+ * Can also be an array of strings, when the dimension spans multiple fields, eg. array("referer_name", "referer_keyword")
+ */
+ public function queryVisitsByDimension($label, $where = '')
+ {
+ if(is_array($label))
+ {
+ $select = implode(", ", $label);
+ $groupBy = $select;
+ }
+ else
+ {
+ $select = $label . " AS label ";
+ $groupBy = 'label';
+ }
+
+ if(!empty($where))
+ {
+ $where = ' AND '.$where;
+ }
+
+ $segmentSql = $this->getSegmentSql();
+ $segment = '';
+ if(!empty($segmentSql['sql']))
+ {
+ $segment = ' AND '.$segmentSql['sql'];
+ }
+
+ $query = "SELECT $select,
+ count(distinct idvisitor) as `". Piwik_Archive::INDEX_NB_UNIQ_VISITORS ."`,
+ count(*) as `". Piwik_Archive::INDEX_NB_VISITS ."`,
+ sum(visit_total_actions) as `". Piwik_Archive::INDEX_NB_ACTIONS ."`,
+ max(visit_total_actions) as `". Piwik_Archive::INDEX_MAX_ACTIONS ."`,
+ sum(visit_total_time) as `". Piwik_Archive::INDEX_SUM_VISIT_LENGTH ."`,
+ sum(case visit_total_actions when 1 then 1 else 0 end) as `". Piwik_Archive::INDEX_BOUNCE_COUNT ."`,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as `". Piwik_Archive::INDEX_NB_VISITS_CONVERTED ."`
+ FROM ".Piwik_Common::prefixTable('log_visit')."
+ WHERE visit_last_action_time >= ?
+ AND visit_last_action_time <= ?
+ AND idsite = ?
+ $where
+ $segment
+ GROUP BY $groupBy
+ ORDER BY NULL";
+ $bind = array_merge( array( $this->getStartDatetimeUTC(),
+ $this->getEndDatetimeUTC(),
+ $this->idsite ),
+ $segmentSql['bind']);
+ $query = $this->db->query($query, $bind );
+ return $query;
+ }
+
+ protected function getSegmentSql()
+ {
+ return $this->segment->getSql();
+ }
+
+ protected function isSegmentAvailableForConversions()
+ {
+ $allowedSegmentsOnConversions = array(
+ 'referer_type',
+ 'referer_name',
+ 'referer_keyword',
+ 'visitor_returning',
+ 'location_country',
+ 'location_continent',
+ 'revenue',
+ 'custom_var_k1',
+ 'custom_var_v1',
+ 'custom_var_k2',
+ 'custom_var_v2',
+ 'custom_var_k3',
+ 'custom_var_v3',
+ 'custom_var_k4',
+ 'custom_var_v4',
+ 'custom_var_k5',
+ 'custom_var_v5',
+ );
+ $segments = $this->segment->getUniqueSqlFields();
+ foreach($segments as $segment)
+ {
+ if(array_search($segment, $allowedSegmentsOnConversions) === false)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @see queryVisitsByDimension() Similar to this function, but queries metrics for the requested dimensions, for each Goal conversion
+ */
+ public function queryConversionsByDimension($label, $where = '')
+ {
+ if(is_array($label))
+ {
+ $select = implode(", ", $label);
+ $groupBy = $select;
+ }
+ else
+ {
+ $select = $label . " AS label ";
+ $groupBy = 'label';
+ }
+ if(!empty($where))
+ {
+ $where = ' AND '.$where;
+ }
+ if(!$this->isSegmentAvailableForConversions())
+ {
+ return false;
+ }
+ $segmentSql = $this->getSegmentSql();
+ $segment = '';
+ if(!empty($segmentSql['sql']))
+ {
+ $segment = ' AND '.$segmentSql['sql'];
+ }
+ $query = "SELECT idgoal,
+ count(*) as `". Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS ."`,
+ sum(revenue) as `". Piwik_Archive::INDEX_GOAL_REVENUE ."`,
+ $select
+ FROM ".Piwik_Common::prefixTable('log_conversion')."
+ WHERE server_time >= ?
+ AND server_time <= ?
+ AND idsite = ?
+ $where
+ $segment
+ GROUP BY idgoal, $groupBy
+ ORDER BY NULL";
+
+ $bind = array_merge( array( $this->getStartDatetimeUTC(),
+ $this->getEndDatetimeUTC(),
+ $this->idsite ),
+ $segmentSql['bind']);
+ $query = $this->db->query($query, $bind);
+ return $query;
+ }
+
public function getDataTableFromArray( $array )
{
@@ -316,82 +475,6 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
$oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS_CONVERTED] += $newRowToAdd[Piwik_Archive::INDEX_NB_VISITS_CONVERTED];
}
- /**
- * @param $label mixed Can be a string, eg. "referer_name", will be aliased as 'label' in the returned rows
- * Can also be an array of strings, when the dimension spans multiple fields, eg. array("referer_name", "referer_keyword")
- */
- public function queryVisitsByDimension($label, $where = '')
- {
- if(is_array($label))
- {
- $select = implode(", ", $label);
- $groupBy = $select;
- }
- else
- {
- $select = $label . " AS label ";
- $groupBy = 'label';
- }
- if(!empty($where))
- {
- $where = ' AND '.$where;
- }
-
- $query = "SELECT $select,
- count(distinct idvisitor) as `". Piwik_Archive::INDEX_NB_UNIQ_VISITORS ."`,
- count(*) as `". Piwik_Archive::INDEX_NB_VISITS ."`,
- sum(visit_total_actions) as `". Piwik_Archive::INDEX_NB_ACTIONS ."`,
- max(visit_total_actions) as `". Piwik_Archive::INDEX_MAX_ACTIONS ."`,
- sum(visit_total_time) as `". Piwik_Archive::INDEX_SUM_VISIT_LENGTH ."`,
- sum(case visit_total_actions when 1 then 1 else 0 end) as `". Piwik_Archive::INDEX_BOUNCE_COUNT ."`,
- sum(case visit_goal_converted when 1 then 1 else 0 end) as `". Piwik_Archive::INDEX_NB_VISITS_CONVERTED ."`
- FROM ".Piwik_Common::prefixTable('log_visit')."
- WHERE visit_last_action_time >= ?
- AND visit_last_action_time <= ?
- AND idsite = ?
- $where
- GROUP BY $groupBy
- ORDER BY NULL";
- $query = $this->db->query($query, array(
- $this->getStartDatetimeUTC(),
- $this->getEndDatetimeUTC(),
- $this->idsite ) );
- return $query;
- }
-
- /**
- * @see queryVisitsByDimension() Similar to this function, but queries metrics for the requested dimensions, for each Goal conversion
- */
- public function queryConversionsByDimension($label, $where = '')
- {
- if(is_array($label))
- {
- $select = implode(", ", $label);
- $groupBy = $select;
- }
- else
- {
- $select = $label . " AS label ";
- $groupBy = 'label';
- }
- if(!empty($where))
- {
- $where = ' AND '.$where;
- }
- $query = "SELECT idgoal,
- count(*) as `". Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS ."`,
- sum(revenue) as `". Piwik_Archive::INDEX_GOAL_REVENUE ."`,
- $select
- FROM ".Piwik_Common::prefixTable('log_conversion')."
- WHERE server_time >= ?
- AND server_time <= ?
- AND idsite = ?
- $where
- GROUP BY idgoal, $groupBy
- ORDER BY NULL";
- $query = $this->db->query($query, array( $this->getStartDatetimeUTC(), $this->getEndDatetimeUTC(), $this->idsite ));
- return $query;
- }
/**
* Given an array of stats, it will process the sum of goal conversions
diff --git a/core/ArchiveProcessing/Period.php b/core/ArchiveProcessing/Period.php
index 513955cbc0..363b1de250 100644
--- a/core/ArchiveProcessing/Period.php
+++ b/core/ArchiveProcessing/Period.php
@@ -252,7 +252,8 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
$archivePeriod = new Piwik_Archive_Single();
$archivePeriod->setSite( $this->site );
$archivePeriod->setPeriod( $period );
- $archivePeriod->prepareArchive();
+ $archivePeriod->setSegment( $this->getSegment() );
+ $archivePeriod->setRequestedReport($this->getRequestedReport());
$periods[] = $archivePeriod;
}
@@ -301,14 +302,24 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
*/
protected function computeNbUniqVisitors()
{
+ // Handling Custom Segment
+ $segmentSql = $this->getSegment()->getSql();
+ $sqlSegmentBind = $segmentSql['bind'];
+ $sqlSegment = $segmentSql['sql'];
+ if(!empty($sqlSegment)) $sqlSegment = ' AND '.$sqlSegment;
+
$query = "
SELECT count(distinct idvisitor) as nb_uniq_visitors
FROM ".Piwik_Common::prefixTable('log_visit')."
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
- AND idsite = ?";
+ AND idsite = ?
+ $sqlSegment
+ ";
- return Zend_Registry::get('db')->fetchOne($query, array( $this->getStartDatetimeUTC(), $this->getEndDatetimeUTC(), $this->idsite ));
+ $bind = array_merge(array( $this->getStartDatetimeUTC(), $this->getEndDatetimeUTC(), $this->idsite ),
+ $sqlSegmentBind);
+ return Zend_Registry::get('db')->fetchOne($query, $bind);
}
/**
@@ -341,7 +352,7 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
$result = Piwik_FetchAll("
SELECT idarchive
FROM $numericTable
- WHERE name='done'
+ WHERE name LIKE 'done%'
AND value = ". Piwik_ArchiveProcessing::DONE_OK_TEMPORARY ."
AND ts_archived < ?", array($yesterday));
diff --git a/core/Segment.php b/core/Segment.php
new file mode 100644
index 0000000000..2f392dbf2a
--- /dev/null
+++ b/core/Segment.php
@@ -0,0 +1,127 @@
+<?php
+class Piwik_Segment
+{
+ /**
+ * @var Piwik_SegmentExpression
+ */
+ protected $segment = null;
+ public function __construct($string, $idSites)
+ {
+ $string = trim($string);
+ $this->string = $string;
+ $this->idSites = $idSites;
+ $segment = new Piwik_SegmentExpression($string);
+ $this->segment = $segment;
+
+ // parse segments
+ $expressions = $segment->parseSubExpressions();
+
+ // convert segments name to sql segment
+ // check that user is allowed to view this segment
+ // and apply a filter to the value to match if necessary (to map DB fields format)
+ $cleanedExpressions = array();
+ foreach($expressions as $expression)
+ {
+ $operand = $expression[Piwik_SegmentExpression::INDEX_OPERAND];
+ $cleanedExpression = $this->getCleanedExpression($operand);
+ $expression[Piwik_SegmentExpression::INDEX_OPERAND] = $cleanedExpression;
+ $cleanedExpressions[] = $expression;
+ }
+ $segment->setSubExpressionsAfterCleanup($cleanedExpressions);
+ }
+
+ public function getPrettyString()
+ {
+ //@TODO
+ }
+
+ public function isEmpty()
+ {
+ return empty($this->string);
+ }
+ protected $availableSegments = array();
+ protected $segmentsHumanReadable = '';
+
+ public function getUniqueSqlFields()
+ {
+ $expressions = $this->segment->parsedSubExpressions;
+ $uniqueFields = array();
+ foreach($expressions as $expression) {
+ $uniqueFields[] = $expression[Piwik_SegmentExpression::INDEX_OPERAND][0];
+ }
+ return $uniqueFields;
+ }
+
+ protected function getCleanedExpression($expression)
+ {
+ if(empty($this->availableSegments))
+ {
+ $this->availableSegments = Piwik_API_API::getInstance()->getSegmentsMetadata($this->idSites, $_hideImplementationData = false);
+ }
+
+ $name = $expression[0];
+ $matchType = $expression[1];
+ $value = $expression[2];
+ $sqlName = '';
+
+ foreach($this->availableSegments as $segment)
+ {
+ if($segment['segment'] != $name)
+ {
+ continue;
+ }
+
+ $sqlName = $segment['sqlSegment'];
+
+ // check permission
+ if(isset($segment['permission'])
+ && $segment['permission'] != 1)
+ {
+ throw new Exception("You do not have enough permission to access the segment ".$name);
+ }
+
+// $this->segmentsHumanReadable[] = $segment['name'] . " " .
+// $this->getNameForMatchType($matchType) .
+// $value;
+
+ // apply presentation filter
+ if(isset($segment['sqlFilter'])
+ && !empty($segment['sqlFilter']))
+ {
+ $value = call_user_func($segment['sqlFilter'], $value, $segment['sqlSegment']);
+ }
+ break;
+ }
+ if(empty($sqlName))
+ {
+ throw new Exception("Segment '$name' is not a supported segment.");
+ }
+ return array( $sqlName, $expression[1], $value );
+ }
+
+ public function getString()
+ {
+ return $this->string;
+ }
+
+ public function getHash()
+ {
+ if(empty($this->string))
+ {
+ return '';
+ }
+ return md5(serialize($this->getSql()));
+ }
+
+ public function getSql()
+ {
+ if($this->isEmpty())
+ {
+ return array('sql' => '', 'bind' => array());
+ }
+ $this->segment->parseSubExpressionsIntoSqlExpressions();
+
+ return $this->segment->getSql();
+ }
+}
+
diff --git a/core/SegmentExpression.php b/core/SegmentExpression.php
new file mode 100644
index 0000000000..35b2454640
--- /dev/null
+++ b/core/SegmentExpression.php
@@ -0,0 +1,228 @@
+<?php
+class Piwik_SegmentExpression
+{
+ const AND_DELIMITER = ';';
+ const OR_DELIMITER = ',';
+
+ const MATCH_EQUAL = '==';
+ const MATCH_NOT_EQUAL = '!=';
+
+ const INDEX_BOOL_OPERATOR = 0;
+ const INDEX_OPERAND = 1;
+
+ function __construct($string)
+ {
+ $this->string = $string;
+ $this->tree = $this->parseTree();
+ }
+ protected $valuesBind = array();
+ protected $parsedTree = array();
+ protected $tree = array();
+
+ /**
+ * Given the array of parsed filters containing, for each filter,
+ * the boolean operator (AND/OR) and the operand,
+ * Will return the array where the filters are in SQL representation
+ */
+ public function parseSubExpressions()
+ {
+ $parsedSubExpressions = array();
+ foreach($this->tree as $id => $leaf)
+ {
+ $operand = $leaf[self::INDEX_OPERAND];
+ $operator = $leaf[self::INDEX_BOOL_OPERATOR];
+ $pattern = '/^(.+?)('.self::MATCH_EQUAL.'|'.self::MATCH_NOT_EQUAL.'){1}(.+)/';
+ $match = preg_match( $pattern, $operand, $matches );
+ if($match == 0)
+ {
+ throw new Exception('Segment parameter \''.$operand.'\' does not appear to have a valid format.');
+ }
+// var_dump($matches);
+
+ $leftMember = $matches[1];
+ $operation = $matches[2];
+ $valueRightMember = $matches[3];
+ $parsedSubExpressions[] = array(
+ self::INDEX_BOOL_OPERATOR => $operator,
+ self::INDEX_OPERAND => array(
+ $leftMember,
+ $operation,
+ $valueRightMember,
+ ));
+ }
+ $this->parsedSubExpressions = $parsedSubExpressions;
+ return $parsedSubExpressions;
+ }
+
+ public function setSubExpressionsAfterCleanup($parsedSubExpressions)
+ {
+ $this->parsedSubExpressions = $parsedSubExpressions;
+ }
+
+ public function getSubExpressions()
+ {
+ return $this->parsedSubExpressions;
+ }
+
+ public function parseSubExpressionsIntoSqlExpressions()
+ {
+ $sqlSubExpressions = array();
+ $this->valuesBind = array();
+ foreach($this->parsedSubExpressions as $leaf)
+ {
+ $operator = $leaf[self::INDEX_BOOL_OPERATOR];
+ $operandDefinition = $leaf[self::INDEX_OPERAND];
+
+ $operand = $this->getSqlMatchFromDefinition($operandDefinition);
+
+ $this->valuesBind[] = $operand[1];
+ $operand = $operand[0];
+ $sqlSubExpressions[] = array(
+ self::INDEX_BOOL_OPERATOR => $operator,
+ self::INDEX_OPERAND => $operand,
+ );
+ }
+ $this->tree = $sqlSubExpressions;
+ }
+
+ /**
+ * Given an array representing one filter operand ( left member , operation , right member)
+ * Will return an array containing
+ * - the SQL substring,
+ * - the values to bind to this substring
+ */
+ // @todo case insensitive?
+ protected function getSqlMatchFromDefinition($def)
+ {
+ $field = $def[0];
+ $matchType = $def[1];
+ $value = $def[2];
+
+ $sqlMatch = '';
+ if($matchType == self::MATCH_EQUAL)
+ {
+ $sqlMatch = '=';
+ }
+ elseif($matchType == self::MATCH_NOT_EQUAL)
+ {
+ $sqlMatch = '<>';
+ }
+ else
+ {
+ throw new Exception("Filter contains the match type '".$matchType."' which is not supported");
+ }
+ return array("$field $sqlMatch ?", $value);
+ }
+
+ /**
+ * Given a filter string,
+ * will parse it into an array where each row contains the boolean operator applied to it,
+ * and the operand
+ */
+ protected function parseTree()
+ {
+ $string = $this->string;
+ if(empty($string)) {
+ return array();
+ }
+ $tree = array();
+ $i = 0;
+ $length = strlen($string);
+ $isBackslash = false;
+ $operand = '';
+ while($i <= $length)
+ {
+ $char = $string[$i];
+
+ $isAND = ($char == self::AND_DELIMITER);
+ $isOR = ($char == self::OR_DELIMITER);
+ $isEnd = ($length == $i+1);
+
+ if($isEnd)
+ {
+ if($isBackslash && ($isAND || $isOR))
+ {
+ $operand = substr($operand, 0, -1);
+ }
+ $operand .= $char;
+ $tree[] = array(self::INDEX_BOOL_OPERATOR => '', self::INDEX_OPERAND => $operand);
+ break;
+ }
+
+ if($isAND && !$isBackslash)
+ {
+ $tree[] = array(self::INDEX_BOOL_OPERATOR => 'AND', self::INDEX_OPERAND => $operand);
+ $operand = '';
+ }
+ elseif($isOR && !$isBackslash)
+ {
+ $tree[] = array(self::INDEX_BOOL_OPERATOR => 'OR', self::INDEX_OPERAND => $operand);
+ $operand = '';
+ }
+ else
+ {
+ if($isBackslash && ($isAND || $isOR))
+ {
+ $operand = substr($operand, 0, -1);
+ }
+ $operand .= $char;
+ }
+ $isBackslash = ($char == "\\");
+ $i++;
+ }
+ return $tree;
+ }
+
+ /**
+ * Given the array of parsed boolean logic, will return
+ * an array containing the full SQL string representing the filter,
+ * and the values to bind to it
+ *
+ * @return array SQL Query, and Bind parameters
+ */
+ public function getSql()
+ {
+ if(count($this->tree) == 0)
+ {
+ throw new Exception("Invalid segment, please specify a valid segment.");
+ }
+ $bind = array();
+ $sql = '';
+ $subExpression = false;
+ foreach($this->tree as $expression)
+ {
+ $operator = $expression[self::INDEX_BOOL_OPERATOR];
+ $operand = $expression[self::INDEX_OPERAND];
+
+ if($operator == 'OR'
+ && !$subExpression)
+ {
+ $sql .= ' (';
+ $subExpression = true;
+ }
+ else
+ {
+ $sql .= ' ';
+ }
+
+ $sql .= $operand;
+
+ if($operator == 'AND'
+ && $subExpression)
+ {
+ $sql .= ')';
+ $subExpression = false;
+ }
+
+ $sql .= " $operator";
+ }
+ if($subExpression)
+ {
+ $sql .= ')';
+ }
+ return array(
+ 'sql' => $sql,
+ 'bind' => $this->valuesBind
+ );
+ }
+} \ No newline at end of file
diff --git a/core/Site.php b/core/Site.php
index 7615c54106..178bec67d8 100644
--- a/core/Site.php
+++ b/core/Site.php
@@ -59,7 +59,7 @@ class Piwik_Site
{
if(!isset(self::$infoSites[$this->id][$name]))
{
- throw new Exception('Requested website was not loaded. ');
+ throw new Exception('Requested field '.$name .' was not loaded in website. ');
}
return self::$infoSites[$this->id][$name];
}
diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php
index e8e363fc12..343172a259 100644
--- a/core/Tracker/Action.php
+++ b/core/Tracker/Action.php
@@ -184,6 +184,14 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
$this->setActionUrl($info['url']);
}
+ static public function getSqlSelectActionId()
+ {
+ $sql = "SELECT idaction, type
+ FROM ".Piwik_Common::prefixTable('log_action')
+ ." WHERE "
+ ." ( hash = CRC32(?) AND name = ? AND type = ? ) ";
+ return $sql;
+ }
/**
* Loads the idaction of the current action name and the current action url.
* These idactions are used in the visitor logging table to link the visit information
@@ -201,10 +209,7 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
return;
}
$idAction = Piwik_Tracker::getDatabase()->fetchAll(
- "SELECT idaction, type
- FROM ".Piwik_Common::prefixTable('log_action')
- ." WHERE "
- ." ( hash = CRC32(?) AND name = ? AND type = ? ) "
+ $this->getSqlSelectActionId()
." OR "
." ( hash = CRC32(?) AND name = ? AND type = ? ) ",
array($this->getActionName(), $this->getActionName(), $this->getActionNameType(),
diff --git a/lang/en.php b/lang/en.php
index 198b53203d..6dc0c8628b 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -40,6 +40,10 @@ $translations = array(
'General_Details' => 'Details',
'General_Default' => 'Default',
'General_Visit' => 'Visit',
+ 'General_VisitorIP' => 'Visitor IP',
+ 'General_VisitType' => 'Visitor type',
+ 'General_NewVisitor' => 'New Visitor',
+ 'General_ReturningVisitor' => 'Returning Visitor',
'General_Date' => 'Date',
'General_Period' => 'Period',
'General_ChooseDate' => 'Choose date',
@@ -79,6 +83,7 @@ $translations = array(
'General_ColumnActionsPerVisit' => 'Actions per Visit',
'General_VisitDuration' => 'Avg. Visit Duration (in seconds)',
'General_ColumnAvgTimeOnSite' => 'Avg. Time on Website',
+ 'General_ColumnVisitDuration' => 'Visit Duration (in seconds)',
'General_ColumnBounceRate' => 'Bounce Rate',
'General_PageBounceRateDefinition' => 'The percentage of visits that started on this page, and left the website straight away.',
'General_ColumnExitRate' => 'Exit rate',
@@ -236,6 +241,10 @@ $translations = array(
'Actions_ColumnPageURL' => 'Page URL',
'Actions_ColumnClickedURL' => 'Clicked URL',
'Actions_ColumnDownloadURL' => 'Download URL',
+ 'Actions_ColumnEntryPageURL' => 'Entry Page URL',
+ 'Actions_ColumnEntryPageTitle' => 'Entry Page title',
+ 'Actions_ColumnExitPageURL' => 'Exit Page URL',
+ 'Actions_ColumnExitPageTitle' => 'Exit Page Title',
'AnonymizeIP_PluginDescription' => 'Anonymize the last byte of visitors IP addresses to comply with your local privacy laws/guidelines.',
'API_PluginDescription' => 'All the data in Piwik is available through simple APIs. This plugin is the web service entry point, that you can call to get your Web Analytics data in xml, json, php, csv, etc.',
'API_QuickDocumentationTitle' => 'API quick documentation',
@@ -672,6 +681,7 @@ $translations = array(
'Referers_ColumnWebsitePage' => 'Website Page',
'Referers_ColumnKeyword' => 'Keyword',
'Referers_ColumnCampaign' => 'Campaign',
+ 'Referers_RefererName' => 'Referrer Name',
'Referers_DetailsByRefererType' => 'Details by Referrer Type',
'Referers_TypeDirectEntries' => '%s direct entries',
'Referers_TypeSearchEngines' => '%s from search engines',
@@ -1066,6 +1076,7 @@ $translations = array(
'UserSettings_WideScreen' => 'Wide Screen',
'UserSettings_ColumnBrowserFamily' => 'Browser family',
'UserSettings_ColumnBrowser' => 'Browser',
+ 'UserSettings_ColumnBrowserVersion' => 'Browser version',
'UserSettings_ColumnPlugin' => 'Plugin',
'UserSettings_ColumnConfiguration' => 'Configuration',
'UserSettings_ColumnOperatingSystem' => 'Operating system',
diff --git a/plugins/API/API.php b/plugins/API/API.php
index f6a0541ca8..e18bd4a391 100644
--- a/plugins/API/API.php
+++ b/plugins/API/API.php
@@ -95,6 +95,64 @@ class Piwik_API_API
return array_map('Piwik_Translate', $translations);
}
+ public function getSegmentsMetadata($idSites = array(), $_hideImplementationData = true)
+ {
+ $segments = array();
+ Piwik_PostEvent('API.getSegmentsMetadata', $segments, $idSites);
+
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => 'General_VisitorIP',
+ 'segment' => 'visitIp',
+ 'sqlSegment' => 'location_ip',
+ 'sqlFilter' => array('Piwik_Common', 'long2ip'),
+ 'permission' => Piwik::isUserHasAdminAccess($idSites),
+ );
+ $segments[] = array(
+ 'type' => 'metric',
+ 'category' => 'Visit',
+ 'name' => 'General_ColumnNbActions',
+ 'segment' => 'actions',
+ 'sqlSegment' => 'visit_total_actions',
+ );
+ $segments[] = array(
+ 'type' => 'metric',
+ 'category' => 'Visit',
+ 'name' => 'General_ColumnVisitDuration',
+ 'segment' => 'visitDuration',
+ 'sqlSegment' => 'visit_total_time',
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => 'General_VisitType',
+ 'segment' => 'visitorType',
+ 'acceptedValues' => 'new, returning',
+ 'sqlSegment' => 'visitor_returning',
+ 'sqlFilter' => create_function('$type', 'return $type == "new" ? 0 : 1;'),
+ );
+//@TODO with 1st party cookies
+// visitCount
+// daysSinceLastVisit
+// visitsToTransaction
+// daysToTransaction
+// visit_goal_converted
+
+ foreach ($segments as &$segment)
+ {
+ $segment['name'] = Piwik_Translate($segment['name']);
+ $segment['category'] = Piwik_Translate($segment['category']);
+
+ if($_hideImplementationData)
+ {
+ unset($segment['sqlFilter']);
+ unset($segment['sqlSegment']);
+ }
+ }
+ return $segments;
+ }
+
/*
* Loads reports metadata, then return the requested one,
* matching optional API parameters.
@@ -139,13 +197,8 @@ class Piwik_API_API
* @param string $idSites Comma separated list of website Ids
* @return array
*/
- public function getReportMetadata($idSites = array())
+ public function getReportMetadata($idSites = '')
{
- if (!is_array($idSites))
- {
- $idSites = array($idSites);
- }
-
$idSites = Piwik_Site::getIdSitesFromIdSitesString($idSites);
$availableReports = array();
@@ -208,7 +261,7 @@ class Piwik_API_API
return $availableReports;
}
- public function getProcessedReport($idSite, $date, $period, $apiModule, $apiAction, $apiParameters = false, $language = false)
+ public function getProcessedReport($idSite, $period, $date, $segment = false, $apiModule, $apiAction, $apiParameters = false, $language = false)
{
if($apiParameters === false)
{
@@ -228,6 +281,7 @@ class Piwik_API_API
'idSite' => $idSite,
'period' => $period,
'date' => $date,
+ 'segment' => $segment,
'format' => 'original',
'serialize' => '0',
'language' => $language,
@@ -256,9 +310,11 @@ class Piwik_API_API
$name = ucfirst($name);
}
$website = new Piwik_Site($idSite);
+// $segment = new Piwik_Segment($segment, $idSite);
return array(
'website' => $website->getName(),
'prettyDate' => Piwik_Period::factory($period, Piwik_Date::factory($date))->getLocalizedLongString(),
+// 'prettySegment' => $segment->getPrettyString(),
'metadata' => $reportMetadata,
'columns' => $columns,
'reportData' => $newReport,
diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php
index 9100104a26..3da2ec0fc7 100644
--- a/plugins/Actions/API.php
+++ b/plugins/Actions/API.php
@@ -33,70 +33,70 @@ class Piwik_Actions_API
* Backward compatibility. Fallsback to getPageTitles() instead.
* @deprecated Deprecated since Piwik 0.5
*/
- public function getActions( $idSite, $period, $date, $expanded = false, $idSubtable = false )
+ public function getActions( $idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false )
{
- return $this->getPageTitles( $idSite, $period, $date, $expanded, $idSubtable );
+ return $this->getPageTitles( $idSite, $period, $date, $segment, $expanded, $idSubtable );
}
- public function getPageUrls( $idSite, $period, $date, $expanded = false, $idSubtable = false )
+ public function getPageUrls( $idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false )
{
- $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_actions_url', $idSite, $period, $date, $expanded, $idSubtable );
+ $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $idSubtable );
$this->filterPageDatatable($dataTable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
- public function getPageUrl( $idSite, $period, $date, $pageUrl)
+ public function getPageUrl( $idSite, $period, $date, $segment = false, $pageUrl)
{
- $callBackParameters = array('Actions_actions_url', $idSite, $period, $date, $expanded = false, $idSubtable = false );
+ $callBackParameters = array('Actions_actions_url', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false );
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $pageUrl, Piwik_Tracker_Action::TYPE_ACTION_URL);
$this->filterPageDatatable($dataTable);
$this->filterActionsDataTable($dataTable);
return $dataTable;
}
- public function getPageTitles( $idSite, $period, $date, $expanded = false, $idSubtable = false)
+ public function getPageTitles( $idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
{
- $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_actions', $idSite, $period, $date, $expanded, $idSubtable);
+ $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_actions', $idSite, $period, $date, $segment, $expanded, $idSubtable);
$this->filterPageDatatable($dataTable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
- public function getPageTitle( $idSite, $period, $date, $pageName)
+ public function getPageTitle( $idSite, $period, $date, $segment = false, $pageName)
{
- $callBackParameters = array('Actions_actions', $idSite, $period, $date, $expanded = false, $idSubtable = false );
+ $callBackParameters = array('Actions_actions', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false );
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $pageName, Piwik_Tracker_Action::TYPE_ACTION_NAME);
$this->filterActionsDataTable($dataTable);
$this->filterPageDatatable($dataTable);
return $dataTable;
}
- public function getDownloads( $idSite, $period, $date, $expanded = false, $idSubtable = false )
+ public function getDownloads( $idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false )
{
- $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_downloads', $idSite, $period, $date, $expanded, $idSubtable );
+ $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_downloads', $idSite, $period, $date, $segment, $expanded, $idSubtable );
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
- public function getDownload( $idSite, $period, $date, $downloadUrl)
+ public function getDownload( $idSite, $period, $date, $segment = false, $downloadUrl)
{
- $callBackParameters = array('Actions_downloads', $idSite, $period, $date, $expanded = false, $idSubtable = false );
+ $callBackParameters = array('Actions_downloads', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false );
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $downloadUrl, Piwik_Tracker_Action::TYPE_DOWNLOAD);
$this->filterActionsDataTable($dataTable);
return $dataTable;
}
- public function getOutlinks( $idSite, $period, $date, $expanded = false, $idSubtable = false )
+ public function getOutlinks( $idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false )
{
- $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_outlink', $idSite, $period, $date, $expanded, $idSubtable );
+ $dataTable = Piwik_Archive::getDataTableFromArchive('Actions_outlink', $idSite, $period, $date, $segment, $expanded, $idSubtable );
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
- public function getOutlink( $idSite, $period, $date, $outlinkUrl)
+ public function getOutlink( $idSite, $period, $date, $segment = false, $outlinkUrl)
{
- $callBackParameters = array('Actions_outlink', $idSite, $period, $date, $expanded = false, $idSubtable = false );
+ $callBackParameters = array('Actions_outlink', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false );
$dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $outlinkUrl, Piwik_Tracker_Action::TYPE_OUTLINK);
$this->filterActionsDataTable($dataTable);
return $dataTable;
@@ -146,7 +146,7 @@ class Piwik_Actions_API
// If we still need to search deeper, call search
$idSubTable = $row->getIdSubDataTable();
// Update the idSubtable in the callback parameter list, to fetch this subtable from the archive
- $callBackParameters[5] = $idSubTable;
+ $callBackParameters[6] = $idSubTable;
$subTable = call_user_func_array(array('Piwik_Archive', 'getDataTableFromArchive'), $callBackParameters);
$found = $this->getFilterPageDatatableSearch($callBackParameters, $search, $actionType, $subTable, $searchTree, $searchCurrentLevel+1);
if($found)
@@ -179,7 +179,7 @@ class Piwik_Actions_API
$dataTable->queueFilter('ColumnCallbackAddColumnPercentage', array('bounce_rate', 'entry_bounce_count', 'entry_nb_visits', 0));
// % Exit = Number of visits that finished on this page / visits on this page
- $dataTable->queueFilter('ColumnCallbackAddColumnPercentage', array('exit_rate', 'exit_nb_visits', 'nb_hits', 0));
+ $dataTable->queueFilter('ColumnCallbackAddColumnPercentage', array('exit_rate', 'exit_nb_visits', 'nb_visits', 0));
}
/**
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index 20860718af..5c2d57d5ae 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -48,10 +48,63 @@ class Piwik_Actions extends Piwik_Plugin
'WidgetsList.add' => 'addWidgets',
'Menu.add' => 'addMenus',
'API.getReportMetadata' => 'getReportMetadata',
+ 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
);
return $hooks;
}
+
+ public function getSegmentsMetadata($notification)
+ {
+ $segments =& $notification->getNotificationObject();
+ $sqlFilter = array($this, 'getIdActionFromString');
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Actions_Actions',
+ 'name' => 'Actions_ColumnEntryPageURL',
+ 'segment' => 'entryPageUrl',
+ 'sqlSegment' => 'visit_entry_idaction_url',
+ 'sqlFilter' => $sqlFilter,
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Actions_Actions',
+ 'name' => 'Actions_ColumnEntryPageTitle',
+ 'segment' => 'entryPageTitle',
+ 'sqlSegment' => 'visit_entry_idaction_name',
+ 'sqlFilter' => $sqlFilter,
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Actions_Actions',
+ 'name' => 'Actions_ColumnExitPageURL',
+ 'segment' => 'exitPageUrl',
+ 'sqlSegment' => 'visit_exit_idaction_url',
+ 'sqlFilter' => $sqlFilter,
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Actions_Actions',
+ 'name' => 'Actions_ColumnExitPageTitle',
+ 'segment' => 'exitPageTitle',
+ 'sqlSegment' => 'visit_exit_idaction_name',
+ 'sqlFilter' => $sqlFilter,
+ );
+ }
+ function getIdActionFromString($string, $sqlField)
+ {
+ // Field is visit_*_idaction_url or visit_*_idaction_name
+ $actionType = strpos($sqlField, '_name') === false
+ ? Piwik_Tracker_Action::TYPE_ACTION_URL
+ : Piwik_Tracker_Action::TYPE_ACTION_NAME;
+
+ $sql = Piwik_Tracker_Action::getSqlSelectActionId();
+ $bind = array($string, $string, $actionType);
+
+ $idAction = Zend_Registry::get('db')->fetchOne($sql, $bind);
+ return $idAction;
+ }
+
public function getReportMetadata($notification)
{
$reports = &$notification->getNotificationObject();
@@ -169,6 +222,9 @@ class Piwik_Actions extends Piwik_Plugin
function archivePeriod( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$dataTableToSum = array(
'Actions_actions',
'Actions_downloads',
@@ -191,6 +247,8 @@ class Piwik_Actions extends Piwik_Plugin
/* @var $archiveProcessing Piwik_ArchiveProcessing */
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$this->actionsTablesByType = array(
Piwik_Tracker_Action::TYPE_ACTION_URL => array(),
Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
@@ -208,29 +266,42 @@ class Piwik_Actions extends Piwik_Plugin
Piwik_Archive::INDEX_PAGE_NB_HITS => 1,
)));
-
+ /*
+ * Handling a custom segment when processing Page reports
+ */
+ $segment = $archiveProcessing->getSegment();
+ $segmentSql = $segment->getSql();
+ $sqlJoinVisitTable = $sqlSegmentWhere = '';
+ if(!$segment->isEmpty())
+ {
+ $sqlJoinVisitTable = "LEFT JOIN ".Piwik_Common::prefixTable('log_visit')." as log_visit ON (log_visit.idvisit = log_link_visit_action.idvisit)";
+ $sqlSegmentWhere = ' AND '.$segmentSql['sql'];
+ }
+ $sqlBind = $segmentSql['bind'];
/*
* Page URLs and Page names, general stats
*/
- //@todo remove join
$queryString = "SELECT name,
type,
idaction,
- count(distinct idvisit) as `". Piwik_Archive::INDEX_NB_VISITS ."`,
- count(distinct idvisitor) as `". Piwik_Archive::INDEX_NB_UNIQ_VISITORS ."`,
+ count(distinct log_link_visit_action.idvisit) as `". Piwik_Archive::INDEX_NB_VISITS ."`,
+ count(distinct log_link_visit_action.idvisitor) as `". Piwik_Archive::INDEX_NB_UNIQ_VISITORS ."`,
count(*) as `". Piwik_Archive::INDEX_PAGE_NB_HITS ."`
FROM ".Piwik_Common::prefixTable('log_link_visit_action')." as log_link_visit_action
LEFT JOIN ".Piwik_Common::prefixTable('log_action')." as log_action ON (log_link_visit_action.%s = idaction)
+ $sqlJoinVisitTable
WHERE server_time >= ?
AND server_time <= ?
- AND idsite = ?
+ AND log_link_visit_action.idsite = ?
AND %s > 0
+ $sqlSegmentWhere
GROUP BY idaction
ORDER BY `". Piwik_Archive::INDEX_PAGE_NB_HITS ."` DESC";
- $this->archiveDayQueryProcess($queryString, "idaction_url", $archiveProcessing);
- $this->archiveDayQueryProcess($queryString, "idaction_name", $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "idaction_url", $sqlBind, $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "idaction_name", $sqlBind, $archiveProcessing);
+
/*
* Entry actions for Page URLs and Page names
*/
@@ -245,9 +316,10 @@ class Piwik_Actions extends Piwik_Plugin
AND visit_last_action_time <= ?
AND idsite = ?
AND %s > 0
+ $sqlSegmentWhere
GROUP BY %s, idaction";
- $this->archiveDayQueryProcess($queryString, "visit_entry_idaction_url", $archiveProcessing);
- $this->archiveDayQueryProcess($queryString, "visit_entry_idaction_name", $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "visit_entry_idaction_url", $sqlBind, $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "visit_entry_idaction_name", $sqlBind, $archiveProcessing);
/*
* Exit actions
@@ -260,24 +332,27 @@ class Piwik_Actions extends Piwik_Plugin
AND visit_last_action_time <= ?
AND idsite = ?
AND %s > 0
+ $sqlSegmentWhere
GROUP BY %s, idaction";
- $this->archiveDayQueryProcess($queryString, "visit_exit_idaction_url", $archiveProcessing);
- $this->archiveDayQueryProcess($queryString, "visit_exit_idaction_name", $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "visit_exit_idaction_url", $sqlBind, $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "visit_exit_idaction_name", $sqlBind, $archiveProcessing);
/*
* Time per action
*/
$queryString = "SELECT %s as idaction,
sum(time_spent_ref_action) as `".Piwik_Archive::INDEX_PAGE_SUM_TIME_SPENT."`
- FROM ".Piwik_Common::prefixTable('log_link_visit_action')."
+ FROM ".Piwik_Common::prefixTable('log_link_visit_action')." AS log_link_visit_action
+ $sqlJoinVisitTable
WHERE server_time >= ?
AND server_time <= ?
- AND idsite = ?
+ AND log_link_visit_action.idsite = ?
AND time_spent_ref_action > 0
AND %s > 0
+ $sqlSegmentWhere
GROUP BY %s, idaction";
- $this->archiveDayQueryProcess($queryString, "idaction_url_ref", $archiveProcessing);
- $this->archiveDayQueryProcess($queryString, "idaction_name_ref", $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "idaction_url_ref", $sqlBind, $archiveProcessing);
+ $this->archiveDayQueryProcess($queryString, "idaction_name_ref", $sqlBind, $archiveProcessing);
// Empty static cache
self::$cacheParsedAction = array();
@@ -286,10 +361,11 @@ class Piwik_Actions extends Piwik_Plugin
$this->archiveDayRecordInDatabase($archiveProcessing);
}
- protected function archiveDayQueryProcess($queryString, $sprintfParameter, $archiveProcessing)
+ protected function archiveDayQueryProcess($queryString, $sprintfParameter, $bind, $archiveProcessing)
{
$queryString = str_replace("%s", $sprintfParameter, $queryString);
- $resultSet = $archiveProcessing->db->query($queryString, array( $archiveProcessing->getStartDatetimeUTC(), $archiveProcessing->getEndDatetimeUTC(), $archiveProcessing->idsite ));
+ $bind = array_merge(array( $archiveProcessing->getStartDatetimeUTC(), $archiveProcessing->getEndDatetimeUTC(), $archiveProcessing->idsite ), $bind);
+ $resultSet = $archiveProcessing->db->query($queryString, $bind);
$modified = $this->updateActionsTableWithRowQuery($resultSet);
return $modified;
}
diff --git a/plugins/CustomVariables/API.php b/plugins/CustomVariables/API.php
index e5af3bd21f..4460b07a80 100644
--- a/plugins/CustomVariables/API.php
+++ b/plugins/CustomVariables/API.php
@@ -27,23 +27,23 @@ class Piwik_CustomVariables_API
return self::$instance;
}
- protected function getDataTable($idSite, $period, $date, $expanded, $idSubtable)
+ protected function getDataTable($idSite, $period, $date, $segment, $expanded, $idSubtable)
{
- $dataTable = Piwik_Archive::getDataTableFromArchive('CustomVariables_valueByName', $idSite, $period, $date, $expanded, $idSubtable);
+ $dataTable = Piwik_Archive::getDataTableFromArchive('CustomVariables_valueByName', $idSite, $period, $date, $segment, $expanded, $idSubtable);
$dataTable->filter('Sort', array(Piwik_Archive::INDEX_NB_VISITS, 'desc', $naturalSort = false, $expanded));
$dataTable->queueFilter('ReplaceColumnNames', array($expanded));
return $dataTable;
}
- public function getCustomVariables($idSite, $period, $date, $expanded = false)
+ public function getCustomVariables($idSite, $period, $date, $segment = false, $expanded = false)
{
- $dataTable = $this->getDataTable($idSite, $period, $date, $expanded, $idSubtable = null);
+ $dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded, $idSubtable = null);
return $dataTable;
}
- public function getCustomVariablesValuesFromNameId($idSite, $period, $date, $idSubtable)
+ public function getCustomVariablesValuesFromNameId($idSite, $period, $date, $segment = false, $idSubtable)
{
- $dataTable = $this->getDataTable($idSite, $period, $date, $expanded = false, $idSubtable);
+ $dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded = false, $idSubtable);
return $dataTable;
}
}
diff --git a/plugins/CustomVariables/CustomVariables.php b/plugins/CustomVariables/CustomVariables.php
index ea21757031..e18681165a 100644
--- a/plugins/CustomVariables/CustomVariables.php
+++ b/plugins/CustomVariables/CustomVariables.php
@@ -41,6 +41,7 @@ class Piwik_CustomVariables extends Piwik_Plugin
'Menu.add' => 'addMenus',
'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
'API.getReportMetadata' => 'getReportMetadata',
+ 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
);
return $hooks;
}
@@ -68,6 +69,29 @@ class Piwik_CustomVariables extends Piwik_Plugin
),
));
}
+
+ public function getSegmentsMetadata($notification)
+ {
+ $segments =& $notification->getNotificationObject();
+ for($i=1; $i <= Piwik_Tracker::MAX_CUSTOM_VARIABLES; $i++)
+ {
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'CustomVariables_CustomVariables',
+ 'name' => Piwik_Translate('CustomVariables_ColumnCustomVariableName').' '.$i,
+ 'segment' => 'customVariableName'.$i,
+ 'sqlSegment' => 'custom_var_k'.$i,
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'CustomVariables_CustomVariables',
+ 'name' => Piwik_Translate('CustomVariables_ColumnCustomVariableValue').' '.$i,
+ 'segment' => 'customVariableValue'.$i,
+ 'sqlSegment' => 'custom_var_v'.$i,
+ );
+ }
+ }
+
/**
* Adds Goal dimensions, so that the dimensions are displayed in the UI Goal Overview page
*/
@@ -90,14 +114,6 @@ class Piwik_CustomVariables extends Piwik_Plugin
$this->maximumRowsInSubDataTable = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_subtable_referers;
}
- function archivePeriod( $notification )
- {
- $archiveProcessing = $notification->getNotificationObject();
-
- $dataTableToSum = 'CustomVariables_valueByName';
- $nameToCount = $archiveProcessing->archiveDataTable($dataTableToSum, null, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable);
- }
-
protected $interestByCustomVariables = array();
protected $interestByCustomVariablesAndValue = array();
@@ -113,6 +129,9 @@ class Piwik_CustomVariables extends Piwik_Plugin
* @var Piwik_ArchiveProcessing_Day
*/
$this->archiveProcessing = $notification->getNotificationObject();
+
+ if(!$this->archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$this->archiveDayAggregate($this->archiveProcessing);
$this->archiveDayRecordInDatabase($this->archiveProcessing);
destroy($this->interestByCustomVariables);
@@ -144,6 +163,9 @@ class Piwik_CustomVariables extends Piwik_Plugin
// Custom Vars names and values metrics for Goals
$query = $archiveProcessing->queryConversionsByDimension($dimensions, $where);
+
+ if($query === false) continue;
+
while($row = $query->fetch() )
{
if(!isset($this->interestByCustomVariables[$row[$keyField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCustomVariables[$row[$keyField]][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
@@ -168,4 +190,14 @@ class Piwik_CustomVariables extends Piwik_Plugin
$archiveProcessing->insertBlobRecord($recordName, $blob);
destroy($table);
}
+
+ function archivePeriod( $notification )
+ {
+ $archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
+ $dataTableToSum = 'CustomVariables_valueByName';
+ $nameToCount = $archiveProcessing->archiveDataTable($dataTableToSum, null, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable);
+ }
}
diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php
index 2fe16bb02d..a7eeed959b 100644
--- a/plugins/Goals/API.php
+++ b/plugins/Goals/API.php
@@ -175,10 +175,10 @@ class Piwik_Goals_API
* @param $columns Comma separated list of metrics to fetch: nb_conversions, conversion_rate, revenue
* @return Piwik_DataTable
*/
- public function get( $idSite, $period, $date, $idGoal = false, $columns = array() )
+ public function get( $idSite, $period, $date, $segment = false, $idGoal = false, $columns = array() )
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$columns = Piwik::getArrayFromApiParameter($columns);
if(empty($columns))
@@ -204,26 +204,26 @@ class Piwik_Goals_API
return $dataTable;
}
- protected function getNumeric( $idSite, $period, $date, $toFetch )
+ protected function getNumeric( $idSite, $period, $date, $segment, $toFetch )
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$dataTable = $archive->getNumeric($toFetch);
return $dataTable;
}
- public function getConversions( $idSite, $period, $date, $idGoal = false )
+ public function getConversions( $idSite, $period, $date, $segment = false, $idGoal = false )
{
- return $this->getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('nb_conversions', $idGoal));
+ return $this->getNumeric( $idSite, $period, $date, $segment, Piwik_Goals::getRecordName('nb_conversions', $idGoal));
}
- public function getConversionRate( $idSite, $period, $date, $idGoal = false )
+ public function getConversionRate( $idSite, $period, $date, $segment = false, $idGoal = false )
{
- return $this->getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('conversion_rate', $idGoal));
+ return $this->getNumeric( $idSite, $period, $date, $segment, Piwik_Goals::getRecordName('conversion_rate', $idGoal));
}
- public function getRevenue( $idSite, $period, $date, $idGoal = false )
+ public function getRevenue( $idSite, $period, $date, $segment = false, $idGoal = false )
{
- return $this->getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('revenue', $idGoal));
+ return $this->getNumeric( $idSite, $period, $date, $segment, Piwik_Goals::getRecordName('revenue', $idGoal));
}
}
diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php
index e799595d52..5517a88a2e 100644
--- a/plugins/Goals/Controller.php
+++ b/plugins/Goals/Controller.php
@@ -275,7 +275,7 @@ class Piwik_Goals_Controller extends Piwik_Controller
// visits converted for returning = nb conversion for this goal
else
{
- $nbVisitsConvertedReturningVisitors = Piwik_Goals_API::getInstance()->getConversions($idSite, $period, $date, $idGoal);
+ $nbVisitsConvertedReturningVisitors = Piwik_Goals_API::getInstance()->getConversions($idSite, $period, $date, $segment=false,$idGoal);
}
// all returning visits
$request = new Piwik_API_Request("method=VisitFrequency.getVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original");
@@ -300,7 +300,7 @@ class Piwik_Goals_Controller extends Piwik_Controller
// new visits converted for a given goal = nb conversion for this goal for new visits
else
{
- $convertedNewVisits = Piwik_Goals_API::getInstance()->getConversions($idSite, $period, $date, $idGoal);
+ $convertedNewVisits = Piwik_Goals_API::getInstance()->getConversions($idSite, $period, $date, $segment=false, $idGoal);
}
// all new visits = all visits - all returning visits
$request = new Piwik_API_Request("method=VisitFrequency.getVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original");
diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php
index 8ec4b4983a..4008b41619 100644
--- a/plugins/Goals/Goals.php
+++ b/plugins/Goals/Goals.php
@@ -208,6 +208,7 @@ class Piwik_Goals extends Piwik_Plugin
{
$returningStr = 'visitor_returning_' . $visitorReturning . '_';
}
+
return 'Goal_' . $returningStr . $idGoalStr . $recordName;
}
@@ -222,6 +223,8 @@ class Piwik_Goals extends Piwik_Plugin
{
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($thisPluginPrefix = 'Goal')) return;
+
$metricsToSum = array( 'nb_conversions', 'revenue');
$goalIdsToSum = Piwik_Tracker_GoalManager::getGoalIds($archiveProcessing->idsite);
@@ -266,9 +269,13 @@ class Piwik_Goals extends Piwik_Plugin
*/
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($thisPluginPrefix = 'Goal')) return;
+
// by processing visitor_returning segment, we can also simply sum and get stats for all goals.
$query = $archiveProcessing->queryConversionsByDimension('visitor_returning');
-
+
+ if($query === false) return;
+
$nb_conversions = $revenue = 0;
$goals = $goalsByVisitorReturning = array();
while($row = $query->fetch() )
diff --git a/plugins/PDFReports/API.php b/plugins/PDFReports/API.php
index 9575e5a92c..5df5631e22 100644
--- a/plugins/PDFReports/API.php
+++ b/plugins/PDFReports/API.php
@@ -263,7 +263,7 @@ class Piwik_PDFReports_API
{
$apiParameters = $action['parameters'];
}
- $report = Piwik_API_API::getInstance()->getProcessedReport($idSite, $date, $period, $apiModule, $apiAction, $apiParameters, $language);
+ $report = Piwik_API_API::getInstance()->getProcessedReport($idSite, $period, $date, $segment = false, $apiModule, $apiAction, $apiParameters, $language);
$websiteName = $report['website'];
$prettyDate = $report['prettyDate'];
$processedReports[] = $report;
diff --git a/plugins/Provider/API.php b/plugins/Provider/API.php
index 82b997ccd1..ade1bcfaea 100644
--- a/plugins/Provider/API.php
+++ b/plugins/Provider/API.php
@@ -32,10 +32,10 @@ class Piwik_Provider_API
return self::$instance;
}
- public function getProvider( $idSite, $period, $date )
+ public function getProvider( $idSite, $period, $date, $segment = false )
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$dataTable = $archive->getDataTable('Provider_hostnameExt');
$dataTable->filter('Sort', array(Piwik_Archive::INDEX_NB_VISITS));
$dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'url', 'Piwik_getHostnameUrl'));
diff --git a/plugins/Provider/Provider.php b/plugins/Provider/Provider.php
index 054fb239cf..826adc90da 100644
--- a/plugins/Provider/Provider.php
+++ b/plugins/Provider/Provider.php
@@ -38,6 +38,7 @@ class Piwik_Provider extends Piwik_Plugin
'WidgetsList.add' => 'addWidget',
'Menu.add' => 'addMenu',
'API.getReportMetadata' => 'getReportMetadata',
+ 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
);
return $hooks;
}
@@ -53,6 +54,18 @@ class Piwik_Provider extends Piwik_Plugin
'dimension' => Piwik_Translate('Provider_ColumnProvider'),
);
}
+
+ public function getSegmentsMetadata($notification)
+ {
+ $segments =& $notification->getNotificationObject();
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => Piwik_Translate('Provider_ColumnProvider'),
+ 'segment' => 'provider',
+ 'sqlSegment' => 'location_provider'
+ );
+ }
function install()
{
@@ -100,6 +113,9 @@ class Piwik_Provider extends Piwik_Plugin
{
$maximumRowsInDataTable = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_standard;
$archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$dataTableToSum = array( 'Provider_hostnameExt' );
$archiveProcessing->archiveDataTable($dataTableToSum, null, $maximumRowsInDataTable);
}
@@ -111,6 +127,8 @@ class Piwik_Provider extends Piwik_Plugin
{
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$recordName = 'Provider_hostnameExt';
$labelSQL = "location_provider";
$interestByProvider = $archiveProcessing->getArrayInterestForLabel($labelSQL);
diff --git a/plugins/Proxy/Controller.php b/plugins/Proxy/Controller.php
index a27164f7b2..8996c26c8f 100644
--- a/plugins/Proxy/Controller.php
+++ b/plugins/Proxy/Controller.php
@@ -109,15 +109,15 @@ class Piwik_Proxy_Controller extends Piwik_Controller
/**
* Output redirection page instead of linking directly to avoid
- * exposing the referer on the Piwik demo.
+ * exposing the referrer on the Piwik demo.
*
* @param string $url (via $_GET)
*/
public function redirect()
{
- // validate referer
- $referer = Piwik_Url::getReferer();
- if(!empty($referer) && (Piwik_Url::getLocalReferer() === false))
+ // validate referrer
+ $referrer = Piwik_Url::getReferer();
+ if(!empty($referrer) && (Piwik_Url::getLocalReferer() === false))
{
exit;
}
diff --git a/plugins/Referers/API.php b/plugins/Referers/API.php
index 7154ec9b29..879ea6e5fd 100644
--- a/plugins/Referers/API.php
+++ b/plugins/Referers/API.php
@@ -29,18 +29,18 @@ class Piwik_Referers_API
/**
* @return Piwik_DataTable
*/
- protected function getDataTable($name, $idSite, $period, $date, $expanded, $idSubtable = null)
+ protected function getDataTable($name, $idSite, $period, $date, $segment, $expanded, $idSubtable = null)
{
- $dataTable = Piwik_Archive::getDataTableFromArchive($name, $idSite, $period, $date, $expanded, $idSubtable = null);
+ $dataTable = Piwik_Archive::getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $idSubtable = null);
$dataTable->filter('Sort', array(Piwik_Archive::INDEX_NB_VISITS, 'desc', $naturalSort = false, $expanded));
$dataTable->queueFilter('ReplaceColumnNames', array($expanded));
return $dataTable;
}
- public function getRefererType($idSite, $period, $date, $typeReferer = false)
+ public function getRefererType($idSite, $period, $date, $segment = false, $typeReferer = false)
{
- $dataTable = $this->getDataTable('Referers_type', $idSite, $period, $date, $expanded = false);
+ $dataTable = $this->getDataTable('Referers_type', $idSite, $period, $date, $segment, $expanded = false);
if($typeReferer !== false)
{
$dataTable->filter('Pattern', array('label', $typeReferer));
@@ -49,20 +49,56 @@ class Piwik_Referers_API
return $dataTable;
}
- public function getKeywords($idSite, $period, $date, $expanded = false)
+ public function getKeywords($idSite, $period, $date, $segment = false, $expanded = false)
{
- $dataTable = $this->getDataTable('Referers_searchEngineByKeyword', $idSite, $period, $date, $expanded);
+ $dataTable = $this->getDataTable('Referers_searchEngineByKeyword', $idSite, $period, $date, $segment, $expanded);
return $dataTable;
}
+
+ public function getKeywordsForPageUrl($idSite, $period, $date, $url)
+ {
+ // Fetch the Top keywords for this page
+ $segment = 'entryPageUrl=='.$url;
+ $table = $this->getKeywords($idSite, $period, $date, $segment);
+ return $this->getLabelsFromTable($table);
+
+ }
+
+ public function getKeywordsForPageTitle($idSite, $period, $date, $title)
+ {
+ $segment = 'entryPageTitle=='.$title;
+ $table = $this->getKeywords($idSite, $period, $date, $segment);
+ return $this->getLabelsFromTable($table);
+ }
+
+ protected function getLabelsFromTable($table)
+ {
+ $request = $_GET;
+ $request['serialize'] = 0;
+
+ // Apply generic filters
+ $response = new Piwik_API_ResponseBuilder($format = 'original', $request);
+ $table = $response->getResponse($table);
+
+ // If period=lastX we only keep the first resultset as we want to return a plain list
+ if($table instanceof Piwik_DataTable_Array)
+ {
+ $tables = $table->getArray();
+ $table = current($tables);
+ }
+ // Keep the response simple, only include keywords
+ $keywords = $table->getColumn('label');
+ return $keywords;
+ }
- public function getSearchEnginesFromKeywordId($idSite, $period, $date, $idSubtable)
+ public function getSearchEnginesFromKeywordId($idSite, $period, $date, $segment = false, $idSubtable)
{
- $dataTable = $this->getDataTable('Referers_searchEngineByKeyword',$idSite, $period, $date, $expanded = false, $idSubtable);
+ $dataTable = $this->getDataTable('Referers_searchEngineByKeyword',$idSite, $period, $date, $segment, $expanded = false, $idSubtable);
$dataTable->queueFilter('ColumnCallbackAddMetadata', array( 'label', 'url', 'Piwik_getSearchEngineUrlFromName') );
$dataTable->queueFilter('MetadataCallbackAddMetadata', array( 'url', 'logo', 'Piwik_getSearchEngineLogoFromUrl') );
// get the keyword and create the URL to the search result page
- $keywords = $this->getKeywords($idSite, $period, $date);
+ $keywords = $this->getKeywords($idSite, $period, $date, $segment);
$subTable = $keywords->getRowFromIdSubDataTable($idSubtable);
if($subTable)
{
@@ -72,20 +108,20 @@ class Piwik_Referers_API
return $dataTable;
}
- public function getSearchEngines($idSite, $period, $date, $expanded = false)
+ public function getSearchEngines($idSite, $period, $date, $segment = false, $expanded = false)
{
- $dataTable = $this->getDataTable('Referers_keywordBySearchEngine',$idSite, $period, $date, $expanded);
+ $dataTable = $this->getDataTable('Referers_keywordBySearchEngine',$idSite, $period, $date, $segment, $expanded);
$dataTable->queueFilter('ColumnCallbackAddMetadata', array( 'label', 'url', 'Piwik_getSearchEngineUrlFromName') );
$dataTable->queueFilter('MetadataCallbackAddMetadata', array( 'url', 'logo', 'Piwik_getSearchEngineLogoFromUrl') );
return $dataTable;
}
- public function getKeywordsFromSearchEngineId($idSite, $period, $date, $idSubtable)
+ public function getKeywordsFromSearchEngineId($idSite, $period, $date, $segment = false, $idSubtable)
{
- $dataTable = $this->getDataTable('Referers_keywordBySearchEngine',$idSite, $period, $date, $expanded = false, $idSubtable);
+ $dataTable = $this->getDataTable('Referers_keywordBySearchEngine',$idSite, $period, $date, $segment, $expanded = false, $idSubtable);
// get the search engine and create the URL to the search result page
- $searchEngines = $this->getSearchEngines($idSite, $period, $date);
+ $searchEngines = $this->getSearchEngines($idSite, $period, $date, $segment);
$searchEngines->applyQueuedFilters();
$subTable = $searchEngines->getRowFromIdSubDataTable($idSubtable);
if($subTable)
@@ -96,27 +132,27 @@ class Piwik_Referers_API
return $dataTable;
}
- public function getCampaigns($idSite, $period, $date, $expanded = false)
+ public function getCampaigns($idSite, $period, $date, $segment = false, $expanded = false)
{
- $dataTable = $this->getDataTable('Referers_keywordByCampaign',$idSite, $period, $date, $expanded);
+ $dataTable = $this->getDataTable('Referers_keywordByCampaign',$idSite, $period, $date, $segment, $expanded);
return $dataTable;
}
- public function getKeywordsFromCampaignId($idSite, $period, $date, $idSubtable)
+ public function getKeywordsFromCampaignId($idSite, $period, $date, $segment = false, $idSubtable)
{
- $dataTable = $this->getDataTable('Referers_keywordByCampaign',$idSite, $period, $date, $expanded = false, $idSubtable);
+ $dataTable = $this->getDataTable('Referers_keywordByCampaign',$idSite, $period, $date, $segment, $expanded = false, $idSubtable);
return $dataTable;
}
- public function getWebsites($idSite, $period, $date, $expanded = false)
+ public function getWebsites($idSite, $period, $date, $segment = false, $expanded = false)
{
- $dataTable = $this->getDataTable('Referers_urlByWebsite',$idSite, $period, $date, $expanded);
+ $dataTable = $this->getDataTable('Referers_urlByWebsite',$idSite, $period, $date, $segment, $expanded);
return $dataTable;
}
- public function getUrlsFromWebsiteId($idSite, $period, $date, $idSubtable)
+ public function getUrlsFromWebsiteId($idSite, $period, $date, $segment = false, $idSubtable)
{
- $dataTable = $this->getDataTable('Referers_urlByWebsite',$idSite, $period, $date, $expanded = false, $idSubtable);
+ $dataTable = $this->getDataTable('Referers_urlByWebsite',$idSite, $period, $date, $segment, $expanded = false, $idSubtable);
// the htmlspecialchars_decode call is for BC for before 1.1
// as the Referer URL was previously encoded in the log tables, but is now recorded raw
$dataTable->queueFilter('ColumnCallbackAddMetadata', array( 'label', 'url', create_function('$label', 'return htmlspecialchars_decode($label);')) );
@@ -124,35 +160,35 @@ class Piwik_Referers_API
return $dataTable;
}
- public function getNumberOfDistinctSearchEngines($idSite, $period, $date)
+ public function getNumberOfDistinctSearchEngines($idSite, $period, $date, $segment = false)
{
- return $this->getNumeric('Referers_distinctSearchEngines', $idSite, $period, $date);
+ return $this->getNumeric('Referers_distinctSearchEngines', $idSite, $period, $date, $segment);
}
- public function getNumberOfDistinctKeywords($idSite, $period, $date)
+ public function getNumberOfDistinctKeywords($idSite, $period, $date, $segment = false)
{
- return $this->getNumeric('Referers_distinctKeywords', $idSite, $period, $date);
+ return $this->getNumeric('Referers_distinctKeywords', $idSite, $period, $date, $segment);
}
- public function getNumberOfDistinctCampaigns($idSite, $period, $date)
+ public function getNumberOfDistinctCampaigns($idSite, $period, $date, $segment = false)
{
- return $this->getNumeric('Referers_distinctCampaigns', $idSite, $period, $date);
+ return $this->getNumeric('Referers_distinctCampaigns', $idSite, $period, $date, $segment);
}
- public function getNumberOfDistinctWebsites($idSite, $period, $date)
+ public function getNumberOfDistinctWebsites($idSite, $period, $date, $segment = false)
{
- return $this->getNumeric('Referers_distinctWebsites', $idSite, $period, $date);
+ return $this->getNumeric('Referers_distinctWebsites', $idSite, $period, $date, $segment);
}
- public function getNumberOfDistinctWebsitesUrls($idSite, $period, $date)
+ public function getNumberOfDistinctWebsitesUrls($idSite, $period, $date, $segment = false)
{
- return $this->getNumeric('Referers_distinctWebsitesUrls', $idSite, $period, $date);
+ return $this->getNumeric('Referers_distinctWebsitesUrls', $idSite, $period, $date, $segment);
}
- private function getNumeric($name, $idSite, $period, $date)
+ private function getNumeric($name, $idSite, $period, $date, $segment)
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
return $archive->getDataTableFromNumeric($name);
}
}
diff --git a/plugins/Referers/Controller.php b/plugins/Referers/Controller.php
index cf1e5318df..afb73f559d 100644
--- a/plugins/Referers/Controller.php
+++ b/plugins/Referers/Controller.php
@@ -51,7 +51,7 @@ class Piwik_Referers_Controller extends Piwik_Controller
echo $view->render();
}
-
+
function getSearchEnginesAndKeywords()
{
$view = Piwik_View::factory('searchEngines_Keywords');
@@ -225,7 +225,7 @@ class Piwik_Referers_Controller extends Piwik_Controller
return $return;
}
- protected $refererTypeToLabel = array(
+ protected $referrerTypeToLabel = array(
Piwik_Common::REFERER_TYPE_DIRECT_ENTRY => 'Referers_DirectEntry',
Piwik_Common::REFERER_TYPE_SEARCH_ENGINE => 'Referers_SearchEngines',
Piwik_Common::REFERER_TYPE_WEBSITE => 'Referers_Websites',
@@ -250,12 +250,12 @@ class Piwik_Referers_Controller extends Piwik_Controller
foreach($columns as $columnName)
{
$columnTranslation = $view->getColumnTranslation($columnName);
- $refererTypeTranslation = $this->refererTypeToLabel[$typeReferer];
+ $referrerTypeTranslation = $this->referrerTypeToLabel[$typeReferer];
$view->setColumnTranslation(
$columnName,
Piwik_Translate('Referers_MetricsFromRefererTypeGraphLegend',
array( Piwik_Translate($columnTranslation),
- Piwik_Translate($refererTypeTranslation)
+ Piwik_Translate($referrerTypeTranslation)
)
)
);
@@ -312,4 +312,83 @@ class Piwik_Referers_Controller extends Piwik_Controller
{
return $this->getNumericValue('Referers.' . __FUNCTION__);
}
+
+ function getKeywordsForPage()
+ {
+ // load as IFRAME or direct include
+ //i18n+widget
+ $requestUrl = '&date=previous1'
+ .'&period=week'
+ .'&idSite='.$this->idSite
+ ;
+
+ $topPageUrlRequest = $requestUrl
+ .'&method=Actions.getPageUrls'
+ .'&filter_limit=50'
+ .'&format=original';
+ $request = new Piwik_API_Request($topPageUrlRequest);
+ $request = $request->process();
+ $tables = $request->getArray();
+ $topPageUrls = $tables[key($tables)];
+ $topPageUrls = $topPageUrls->getRowsMetadata('url');
+ $topPageUrl = current(array_values($topPageUrls));
+
+ if(empty($topPageUrl))
+ {
+ $topPageUrl = $this->site->getMainUrl();
+ }
+ $url = $topPageUrl;
+
+ // HTML
+ $api = Piwik_Url::getCurrentUrlWithoutFileName()
+ .'?module=API&method=Referers.getKeywordsForPageUrl'
+ .'&format=php'
+ .'&filter_limit=10';
+
+ $api .= $requestUrl;
+ $code = '
+// This function will call the API to get best keyword for current URL.
+// Then it writes the list of best keywords in a HTML list
+function DisplayTopKeywords($url = "")
+{
+ // Get the Keywords data
+ $url = empty($url) ? "http://". $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] : $url;
+ $api = "'.$api.'&url=" . urlencode($url);
+ $keywords = @unserialize(file_get_contents($api));
+ if($keywords === false) {
+ echo "Error while fetching the <a href=\'$api\'>Top Keywords from Piwik</a>"; return;
+ }
+
+ // Display the list in HTML
+ $output = "<h2>Top Keywords for <a href=\'$url\'>$url</a></h2><ul>";
+ foreach($keywords as $keyword) {
+ $output .= "<li>". $keyword[0]. "</li>";
+ }
+ if(empty($keywords)) { $output .= "Nothing yet..."; }
+ $output .= "</ul>";
+ echo $output;
+}
+';
+
+ $jsonRequest = str_replace('format=php', 'format=json', $api);
+ echo "<p>This widget is designed to work in your website directly.
+ This widget makes it easy to use Piwik to <i>automatically display the list of Top Keywords</i>, for each of your website Page URLs.</p>
+ <p>
+ <b>Example API URL</b> - For example if you would like to get the top 10 keywords, used last week, to land on the page <a target='_blank' href='$topPageUrl'>$topPageUrl</a>,
+ in format JSON: you would dynamically fetch the data <a target='_blank' href='$jsonRequest&url=".urlencode($topPageUrl)."'>this API request Url</a>. Make sure you encode the 'url' parameter in the URL.</p>
+
+ <p><b>PHP Function ready to use!</b> - If you use PHP on your website, we have prepared a small code snippet that you can copy paste in your Website PHP files. You can then simply call the function <code>DisplayTopKeywords();</code> anywhere in your template, at the bottom of the content or in your blog sidebar.
+ If you run this code in your page $topPageUrl, it would output the following:";
+
+ echo "<div style='width:400px;margin-left:20px;padding:10px;border:1px solid black;'>";
+ eval($code);
+ DisplayTopKeywords($topPageUrl);
+ echo "</div>
+ ";
+
+ echo "<br/><p>Here is the PHP function that you can paste in your pages:</P>
+ <textarea cols=60 rows=8>&lt;?php\n" . htmlspecialchars($code) . "\n DisplayTopKeywords();</textarea>";
+
+ }
+
}
diff --git a/plugins/Referers/Referers.php b/plugins/Referers/Referers.php
index 75ec3c5a29..6ccda84044 100644
--- a/plugins/Referers/Referers.php
+++ b/plugins/Referers/Referers.php
@@ -46,6 +46,7 @@ class Piwik_Referers extends Piwik_Plugin
'Menu.add' => 'addMenus',
'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
'API.getReportMetadata' => 'getReportMetadata',
+ 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
);
return $hooks;
}
@@ -92,6 +93,40 @@ class Piwik_Referers extends Piwik_Plugin
));
}
+ public function getSegmentsMetadata($notification)
+ {
+ $segments =& $notification->getNotificationObject();
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Referers_Referers',
+ 'name' => 'Referers_ColumnRefererType',
+ 'segment' => 'referrerType',
+ 'acceptedValues' => 'direct, search, website, campaign',
+ 'sqlSegment' => 'referer_type',
+ 'sqlFilter' => 'Piwik_getRefererTypeFromShortName',
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Referers_Referers',
+ 'name' => 'Referers_ColumnKeyword',
+ 'segment' => 'referrerKeyword',
+ 'sqlSegment' => 'referer_keyword',
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Referers_Referers',
+ 'name' => 'Referers_RefererName',
+ 'segment' => 'referrerName',
+ 'sqlSegment' => 'referer_name',
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Referers_Referers',
+ 'name' => 'Live_Referrer_URL',
+ 'segment' => 'referrerUrl',
+ 'sqlSegment' => 'referer_url',
+ );
+ }
/**
* Adds Referer widgets
@@ -103,6 +138,7 @@ class Piwik_Referers extends Piwik_Plugin
Piwik_AddWidget( 'Referers_Referers', 'Referers_WidgetExternalWebsites', 'Referers', 'getWebsites');
Piwik_AddWidget( 'Referers_Referers', 'Referers_WidgetSearchEngines', 'Referers', 'getSearchEngines');
Piwik_AddWidget( 'Referers_Referers', 'Referers_WidgetOverview', 'Referers', 'getRefererType');
+ Piwik_AddWidget( 'Referers_Referers', 'Top Keywords for Page URL', 'Referers', 'getKeywordsForPage');
}
/**
@@ -173,6 +209,8 @@ class Piwik_Referers extends Piwik_Plugin
{
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$dataTableToSum = array(
'Referers_type',
'Referers_keywordBySearchEngine',
@@ -236,6 +274,8 @@ 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);
diff --git a/plugins/UserCountry/API.php b/plugins/UserCountry/API.php
index cdab67c89e..4cfe49763c 100644
--- a/plugins/UserCountry/API.php
+++ b/plugins/UserCountry/API.php
@@ -33,9 +33,9 @@ class Piwik_UserCountry_API
return self::$instance;
}
- public function getCountry( $idSite, $period, $date )
+ public function getCountry( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserCountry_country', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserCountry_country', $idSite, $period, $date, $segment);
// apply filter on the whole datatable in order the inline search to work (searches are done on "beautiful" label)
$dataTable->filter('ColumnCallbackAddMetadata', array('label', 'code', create_function('$label', 'return $label;')));
$dataTable->filter('ColumnCallbackAddMetadata', array('label', 'logo', 'Piwik_getFlagFromCode'));
@@ -45,28 +45,28 @@ class Piwik_UserCountry_API
return $dataTable;
}
- public function getContinent( $idSite, $period, $date )
+ public function getContinent( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserCountry_continent', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserCountry_continent', $idSite, $period, $date, $segment);
$dataTable->filter('ColumnCallbackReplace', array('label', 'Piwik_ContinentTranslate'));
$dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'code', create_function('$label', 'return $label;')));
return $dataTable;
}
- protected function getDataTable($name, $idSite, $period, $date)
+ protected function getDataTable($name, $idSite, $period, $date, $segment)
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$dataTable = $archive->getDataTable($name);
$dataTable->filter('Sort', array(Piwik_Archive::INDEX_NB_VISITS));
$dataTable->queueFilter('ReplaceColumnNames');
return $dataTable;
}
- public function getNumberOfDistinctCountries($idSite, $period, $date)
+ public function getNumberOfDistinctCountries($idSite, $period, $date, $segment = false)
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
return $archive->getDataTableFromNumeric('UserCountry_distinctCountries');
}
}
diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php
index 226fe80026..db8d80a541 100644
--- a/plugins/UserCountry/UserCountry.php
+++ b/plugins/UserCountry/UserCountry.php
@@ -36,10 +36,44 @@ class Piwik_UserCountry extends Piwik_Plugin
'Menu.add' => 'addMenu',
'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
'API.getReportMetadata' => 'getReportMetadata',
+ 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
);
return $hooks;
}
+ function addWidgets()
+ {
+ Piwik_AddWidget( 'General_Visitors', 'UserCountry_WidgetContinents', 'UserCountry', 'getContinent');
+ Piwik_AddWidget( 'General_Visitors', 'UserCountry_WidgetCountries', 'UserCountry', 'getCountry');
+ }
+
+ function addMenu()
+ {
+ Piwik_AddMenu('General_Visitors', 'UserCountry_SubmenuLocations', array('module' => 'UserCountry', 'action' => 'index'));
+ }
+
+
+ public function getSegmentsMetadata($notification)
+ {
+ $segments =& $notification->getNotificationObject();
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => Piwik_Translate('UserCountry_Country'),
+ 'segment' => 'country',
+ 'sqlSegment' => 'location_country',
+ 'acceptedValues' => 'de, us, fr, in, es, etc.'
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => Piwik_Translate('UserCountry_Continent'),
+ 'segment' => 'continent',
+ 'sqlSegment' => 'location_continent',
+ 'acceptedValues' => 'eur, asi, amc, amn, ams, afr, ant, oce'
+ );
+ }
+
public function getReportMetadata($notification)
{
$reports = &$notification->getNotificationObject();
@@ -49,6 +83,7 @@ class Piwik_UserCountry extends Piwik_Plugin
'module' => 'UserCountry',
'action' => 'getCountry',
'dimension' => Piwik_Translate('UserCountry_Country'),
+ ''
);
$reports[] = array(
@@ -60,17 +95,6 @@ class Piwik_UserCountry extends Piwik_Plugin
);
}
- function addWidgets()
- {
- Piwik_AddWidget( 'General_Visitors', 'UserCountry_WidgetContinents', 'UserCountry', 'getContinent');
- Piwik_AddWidget( 'General_Visitors', 'UserCountry_WidgetCountries', 'UserCountry', 'getCountry');
- }
-
- function addMenu()
- {
- Piwik_AddMenu('General_Visitors', 'UserCountry_SubmenuLocations', array('module' => 'UserCountry', 'action' => 'index'));
- }
-
function getReportsWithGoalMetrics( $notification )
{
$dimensions =& $notification->getNotificationObject();
@@ -92,6 +116,8 @@ class Piwik_UserCountry extends Piwik_Plugin
{
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$dataTableToSum = array(
'UserCountry_country',
'UserCountry_continent',
@@ -105,6 +131,9 @@ class Piwik_UserCountry extends Piwik_Plugin
function archiveDay($notification)
{
$archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$this->archiveDayAggregateVisits($archiveProcessing);
$this->archiveDayAggregateGoals($archiveProcessing);
$this->archiveDayRecordInDatabase($archiveProcessing);
@@ -122,6 +151,9 @@ class Piwik_UserCountry extends Piwik_Plugin
protected function archiveDayAggregateGoals($archiveProcessing)
{
$query = $archiveProcessing->queryConversionsByDimension(array("location_continent","location_country"));
+
+ if($query === false) return;
+
while($row = $query->fetch() )
{
if(!isset($this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
diff --git a/plugins/UserSettings/API.php b/plugins/UserSettings/API.php
index 2a97d4af09..adcdbb6f73 100644
--- a/plugins/UserSettings/API.php
+++ b/plugins/UserSettings/API.php
@@ -31,10 +31,10 @@ class Piwik_UserSettings_API
return self::$instance;
}
- protected function getDataTable($name, $idSite, $period, $date)
+ protected function getDataTable($name, $idSite, $period, $date, $segment)
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$dataTable = $archive->getDataTable($name);
$dataTable->filter('Sort', array(Piwik_Archive::INDEX_NB_VISITS));
$dataTable->queueFilter('ReplaceColumnNames');
@@ -42,62 +42,62 @@ class Piwik_UserSettings_API
return $dataTable;
}
- public function getResolution( $idSite, $period, $date )
+ public function getResolution( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserSettings_resolution', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserSettings_resolution', $idSite, $period, $date, $segment);
return $dataTable;
}
- public function getConfiguration( $idSite, $period, $date )
+ public function getConfiguration( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserSettings_configuration', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserSettings_configuration', $idSite, $period, $date, $segment);
$dataTable->queueFilter('ColumnCallbackReplace', array('label', 'Piwik_getConfigurationLabel'));
return $dataTable;
}
- public function getOS( $idSite, $period, $date )
+ public function getOS( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserSettings_os', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserSettings_os', $idSite, $period, $date, $segment);
$dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'logo', 'Piwik_getOSLogo'));
$dataTable->queueFilter('ColumnCallbackAddMetadata', array( 'label', 'shortLabel', 'Piwik_getOSShortLabel') );
$dataTable->queueFilter('ColumnCallbackReplace', array( 'label', 'Piwik_getOSLabel') );
return $dataTable;
}
- public function getBrowser( $idSite, $period, $date )
+ public function getBrowser( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserSettings_browser', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserSettings_browser', $idSite, $period, $date, $segment);
$dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'logo', 'Piwik_getBrowsersLogo'));
$dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'shortLabel', 'Piwik_getBrowserShortLabel'));
$dataTable->queueFilter('ColumnCallbackReplace', array('label', 'Piwik_getBrowserLabel'));
return $dataTable;
}
- public function getBrowserType( $idSite, $period, $date )
+ public function getBrowserType( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserSettings_browserType', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserSettings_browserType', $idSite, $period, $date, $segment);
$dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'shortLabel', 'ucfirst'));
$dataTable->queueFilter('ColumnCallbackReplace', array('label', 'Piwik_getBrowserTypeLabel'));
return $dataTable;
}
- public function getWideScreen( $idSite, $period, $date )
+ public function getWideScreen( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('UserSettings_wideScreen', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserSettings_wideScreen', $idSite, $period, $date, $segment);
$dataTable->queueFilter('ColumnCallbackAddMetadata', array('label', 'logo', 'Piwik_getScreensLogo'));
$dataTable->queueFilter('ColumnCallbackReplace', array('label', 'ucfirst'));
return $dataTable;
}
- public function getPlugin( $idSite, $period, $date )
+ public function getPlugin( $idSite, $period, $date, $segment = false )
{
// fetch all archive data required
- $dataTable = $this->getDataTable('UserSettings_plugin', $idSite, $period, $date);
- $browserTypes = $this->getDataTable('UserSettings_browserType', $idSite, $period, $date);
- $archive = Piwik_Archive::build($idSite, $period, $date);
+ $dataTable = $this->getDataTable('UserSettings_plugin', $idSite, $period, $date, $segment);
+ $browserTypes = $this->getDataTable('UserSettings_browserType', $idSite, $period, $date, $segment);
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment);
$visitsSums = $archive->getNumeric('nb_visits');
- // check wether given tables are arrays
+ // check whether given tables are arrays
if($dataTable instanceof Piwik_DataTable_Array) {
$tableArray = $dataTable->getArray();
$browserTypesArray = $browserTypes->getArray();
diff --git a/plugins/UserSettings/UserSettings.php b/plugins/UserSettings/UserSettings.php
index 9b309f1953..08b6485ef6 100644
--- a/plugins/UserSettings/UserSettings.php
+++ b/plugins/UserSettings/UserSettings.php
@@ -41,16 +41,72 @@ class Piwik_UserSettings extends Piwik_Plugin
* Defines API reports.
* Also used to define Widgets.
*
- * @array Category, Report Name, API Module, API action, Translated column name
+ * @array Category, Report Name, API Module, API action, Translated column name,
+ * $segment, $sqlSegment, $acceptedValues, $sqlFilter
*/
protected $reportMetadata = array(
- array( 'UserSettings_VisitorSettings', 'UserSettings_WidgetResolutions', 'UserSettings', 'getResolution', 'UserSettings_ColumnResolution' ),
- array( 'UserSettings_VisitorSettings', 'UserSettings_WidgetBrowsers', 'UserSettings', 'getBrowser', 'UserSettings_ColumnBrowser'),
- array( 'UserSettings_VisitorSettings', 'UserSettings_WidgetPlugins', 'UserSettings', 'getPlugin', 'UserSettings_ColumnPlugin'),
- array( 'UserSettings_VisitorSettings', 'UserSettings_WidgetWidescreen', 'UserSettings', 'getWideScreen', 'UserSettings_ColumnTypeOfScreen'),
- array( 'UserSettings_VisitorSettings', 'UserSettings_WidgetBrowserFamilies', 'UserSettings', 'getBrowserType', 'UserSettings_ColumnBrowserFamily'),
- array( 'UserSettings_VisitorSettings', 'UserSettings_WidgetOperatingSystems', 'UserSettings', 'getOS', 'UserSettings_ColumnOperatingSystem'),
- array( 'UserSettings_VisitorSettings', 'UserSettings_WidgetGlobalVisitors', 'UserSettings', 'getConfiguration', 'UserSettings_ColumnConfiguration'),
+ array( 'UserSettings_VisitorSettings',
+ 'UserSettings_WidgetResolutions',
+ 'UserSettings',
+ 'getResolution',
+ 'UserSettings_ColumnResolution',
+ 'resolution',
+ 'config_resolution',
+ '1280x1024, 800x600, etc.',
+ ),
+
+ array( 'UserSettings_VisitorSettings',
+ 'UserSettings_WidgetBrowsers',
+ 'UserSettings',
+ 'getBrowser',
+ 'UserSettings_ColumnBrowser',
+ 'browserName',
+ 'config_browser_name',
+ 'FF, IE, CH, SF, OP, etc.',),
+
+ // Only used as a Segment, not as a widget
+ array( false,
+ false,
+ 'UserSettings',
+ 'getBrowser',
+ 'UserSettings_ColumnBrowserVersion',
+ 'browserVersion',
+ 'config_browser_version',
+ '1.0, 8.0, etc.',),
+
+
+ array( 'UserSettings_VisitorSettings',
+ 'UserSettings_WidgetPlugins',
+ 'UserSettings',
+ 'getPlugin',
+ 'UserSettings_ColumnPlugin'),
+
+ array( 'UserSettings_VisitorSettings',
+ 'UserSettings_WidgetWidescreen',
+ 'UserSettings',
+ 'getWideScreen',
+ 'UserSettings_ColumnTypeOfScreen'),
+
+ array( 'UserSettings_VisitorSettings',
+ 'UserSettings_WidgetBrowserFamilies',
+ 'UserSettings',
+ 'getBrowserType',
+ 'UserSettings_ColumnBrowserFamily'),
+
+ array( 'UserSettings_VisitorSettings',
+ 'UserSettings_WidgetOperatingSystems',
+ 'UserSettings',
+ 'getOS',
+ 'UserSettings_ColumnOperatingSystem',
+ 'operatingSystem',
+ 'config_os',
+ 'WXP, WI7, MAC, LIN, AND, IPD, etc.'),
+
+ array( 'UserSettings_VisitorSettings',
+ 'UserSettings_WidgetGlobalVisitors',
+ 'UserSettings',
+ 'getConfiguration',
+ 'UserSettings_ColumnConfiguration'),
);
/*
@@ -64,6 +120,7 @@ class Piwik_UserSettings extends Piwik_Plugin
'WidgetsList.add' => 'addWidgets',
'Menu.add' => 'addMenu',
'API.getReportMetadata' => 'getReportMetadata',
+ 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
);
return $hooks;
}
@@ -78,6 +135,8 @@ class Piwik_UserSettings extends Piwik_Plugin
foreach($this->reportMetadata as $report)
{
list( $category, $name, $apiModule, $apiAction, $columnName ) = $report;
+ if($category == false) continue;
+
$report = array(
'category' => Piwik_Translate($category),
'name' => Piwik_Translate($name),
@@ -99,6 +158,25 @@ class Piwik_UserSettings extends Piwik_Plugin
$reports[] = $report;
}
}
+
+ public function getSegmentsMetadata($notification)
+ {
+ $segments =& $notification->getNotificationObject();
+ foreach($this->reportMetadata as $report)
+ {
+ @list( $category, $name, $apiModule, $apiAction, $columnName, $segment, $sqlSegment, $acceptedValues, $sqlFilter ) = $report;
+ if(empty($segment)) continue;
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => $columnName,
+ 'segment' => $segment,
+ 'acceptedValues' => $acceptedValues,
+ 'sqlSegment' => $sqlSegment,
+ 'sqlFilter' => isset($sqlFilter) ? $sqlFilter : false,
+ );
+ }
+ }
/**
* Adds the various User Settings widgets
@@ -109,6 +187,7 @@ class Piwik_UserSettings extends Piwik_Plugin
foreach($this->reportMetadata as $report)
{
list( $category, $name, $controllerName, $controllerAction ) = $report;
+ if($category == false) continue;
Piwik_AddWidget( $category, $name, $controllerName, $controllerAction );
}
}
@@ -136,6 +215,9 @@ class Piwik_UserSettings extends Piwik_Plugin
$columnToSortByBeforeTruncation = Piwik_Archive::INDEX_NB_VISITS;
$archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$this->archiveProcessing = $archiveProcessing;
$recordName = 'UserSettings_configuration';
@@ -191,6 +273,9 @@ class Piwik_UserSettings extends Piwik_Plugin
function archivePeriod( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$maximumRowsInDataTable = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_standard;
$dataTableToSum = array(
diff --git a/plugins/VisitFrequency/VisitFrequency.php b/plugins/VisitFrequency/VisitFrequency.php
index 82c4b63297..f8eacdd4ca 100644
--- a/plugins/VisitFrequency/VisitFrequency.php
+++ b/plugins/VisitFrequency/VisitFrequency.php
@@ -79,6 +79,8 @@ class Piwik_VisitFrequency extends Piwik_Plugin
{
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$numericToSum = array(
'nb_visits_returning',
'nb_actions_returning',
@@ -95,6 +97,9 @@ class Piwik_VisitFrequency extends Piwik_Plugin
/* @var $archiveProcessing Piwik_ArchiveProcessing */
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
+ //@TODO Segments
$query = "SELECT count(distinct idvisitor) as nb_uniq_visitors_returning,
count(*) as nb_visits_returning,
sum(visit_total_actions) as nb_actions_returning,
diff --git a/plugins/VisitTime/API.php b/plugins/VisitTime/API.php
index 917c9cc4b2..843ea6687e 100644
--- a/plugins/VisitTime/API.php
+++ b/plugins/VisitTime/API.php
@@ -26,10 +26,10 @@ class Piwik_VisitTime_API
return self::$instance;
}
- protected function getDataTable($name, $idSite, $period, $date )
+ protected function getDataTable($name, $idSite, $period, $date, $segment )
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$dataTable = $archive->getDataTable($name);
$dataTable->filter('Sort', array('label', 'asc', true));
$dataTable->queueFilter('ColumnCallbackReplace', array('label', 'Piwik_getTimeLabel'));
@@ -37,14 +37,14 @@ class Piwik_VisitTime_API
return $dataTable;
}
- public function getVisitInformationPerLocalTime( $idSite, $period, $date )
+ public function getVisitInformationPerLocalTime( $idSite, $period, $date, $segment = false )
{
- return $this->getDataTable('VisitTime_localTime', $idSite, $period, $date );
+ return $this->getDataTable('VisitTime_localTime', $idSite, $period, $date, $segment );
}
- public function getVisitInformationPerServerTime( $idSite, $period, $date )
+ public function getVisitInformationPerServerTime( $idSite, $period, $date, $segment = false )
{
- return $this->getDataTable('VisitTime_serverTime', $idSite, $period, $date );
+ return $this->getDataTable('VisitTime_serverTime', $idSite, $period, $date, $segment );
}
}
diff --git a/plugins/VisitTime/VisitTime.php b/plugins/VisitTime/VisitTime.php
index f173364bca..8a28162aff 100644
--- a/plugins/VisitTime/VisitTime.php
+++ b/plugins/VisitTime/VisitTime.php
@@ -36,6 +36,7 @@ class Piwik_VisitTime extends Piwik_Plugin
'Menu.add' => 'addMenu',
'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
'API.getReportMetadata' => 'getReportMetadata',
+ 'API.getSegmentsMetadata' => 'getSegmentsMetadata',
);
return $hooks;
}
@@ -81,9 +82,33 @@ class Piwik_VisitTime extends Piwik_Plugin
);
}
+ public function getSegmentsMetadata($notification)
+ {
+ $segments =& $notification->getNotificationObject();
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => Piwik_Translate('VisitTime_ColumnServerTime'),
+ 'segment' => 'visitServerHour',
+ 'sqlSegment' => 'HOUR(visit_last_action_time)',
+ 'acceptedValues' => implode(',', range(0, 23, 1))
+ );
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => 'Visit',
+ 'name' => Piwik_Translate('VisitTime_ColumnLocalTime'),
+ 'segment' => 'visitLocalHour',
+ 'sqlSegment' => 'HOUR(visitor_localtime)',
+ 'acceptedValues' => implode(',', range(0, 23, 1))
+ );
+ }
+
function archivePeriod( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$dataTableToSum = array(
'VisitTime_localTime',
'VisitTime_serverTime',
@@ -94,6 +119,9 @@ class Piwik_VisitTime extends Piwik_Plugin
public function archiveDay( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
+
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$this->archiveDayAggregateVisits($archiveProcessing);
$this->archiveDayAggregateGoals($archiveProcessing);
$this->archiveDayRecordInDatabase($archiveProcessing);
@@ -126,6 +154,9 @@ class Piwik_VisitTime extends Piwik_Plugin
protected function archiveDayAggregateGoals($archiveProcessing)
{
$query = $archiveProcessing->queryConversionsByDimension("HOUR(server_time)");
+
+ if($query === false) return;
+
$goalByServerTime = array();
while($row = $query->fetch())
{
diff --git a/plugins/VisitorInterest/API.php b/plugins/VisitorInterest/API.php
index 78b927a9ed..87ddc924b6 100644
--- a/plugins/VisitorInterest/API.php
+++ b/plugins/VisitorInterest/API.php
@@ -26,10 +26,10 @@ class Piwik_VisitorInterest_API
return self::$instance;
}
- protected function getDataTable($name, $idSite, $period, $date)
+ protected function getDataTable($name, $idSite, $period, $date, $segment)
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$dataTable = $archive->getDataTable($name);
$dataTable->filter('Sort',array(Piwik_Archive::INDEX_NB_VISITS));
$dataTable->queueFilter('ReplaceColumnNames');
@@ -37,16 +37,16 @@ class Piwik_VisitorInterest_API
return $dataTable;
}
- public function getNumberOfVisitsPerVisitDuration( $idSite, $period, $date )
+ public function getNumberOfVisitsPerVisitDuration( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('VisitorInterest_timeGap', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('VisitorInterest_timeGap', $idSite, $period, $date, $segment);
$dataTable->queueFilter('ColumnCallbackReplace', array('label', 'Piwik_getDurationLabel'));
return $dataTable;
}
- public function getNumberOfVisitsPerPage( $idSite, $period, $date )
+ public function getNumberOfVisitsPerPage( $idSite, $period, $date, $segment = false )
{
- $dataTable = $this->getDataTable('VisitorInterest_pageGap', $idSite, $period, $date);
+ $dataTable = $this->getDataTable('VisitorInterest_pageGap', $idSite, $period, $date, $segment);
$dataTable->queueFilter('ColumnCallbackReplace', array('label', 'Piwik_getPageGapLabel'));
return $dataTable;
}
diff --git a/plugins/VisitorInterest/VisitorInterest.php b/plugins/VisitorInterest/VisitorInterest.php
index 3b837b6ae6..6e7484f656 100644
--- a/plugins/VisitorInterest/VisitorInterest.php
+++ b/plugins/VisitorInterest/VisitorInterest.php
@@ -110,6 +110,8 @@ class Piwik_VisitorInterest extends Piwik_Plugin
{
$archiveProcessing = $notification->getNotificationObject();
+ if(!$archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$dataTableToSum = array(
'VisitorInterest_timeGap',
'VisitorInterest_pageGap',
@@ -121,6 +123,8 @@ class Piwik_VisitorInterest extends Piwik_Plugin
{
$this->archiveProcessing = $notification->getNotificationObject();
+ if(!$this->archiveProcessing->shouldProcessReportsForPlugin($this->getPluginName())) return;
+
$recordName = 'VisitorInterest_timeGap';
$tableTimegap = $this->getTableTimeGap();
$this->archiveProcessing->insertBlobRecord($recordName, $tableTimegap->getSerialized());
diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php
index 572e7ceb89..6545e1087b 100644
--- a/plugins/VisitsSummary/API.php
+++ b/plugins/VisitsSummary/API.php
@@ -26,10 +26,10 @@ class Piwik_VisitsSummary_API
return self::$instance;
}
- public function get( $idSite, $period, $date, $columns = false)
+ public function get( $idSite, $period, $date, $segment = false, $columns = false)
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
// array values are comma separated
$columns = Piwik::getArrayFromApiParameter($columns);
@@ -92,52 +92,52 @@ class Piwik_VisitsSummary_API
return $dataTable;
}
- protected function getNumeric( $idSite, $period, $date, $toFetch )
+ protected function getNumeric( $idSite, $period, $date, $segment, $toFetch )
{
Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
+ $archive = Piwik_Archive::build($idSite, $period, $date, $segment );
$dataTable = $archive->getNumeric($toFetch);
return $dataTable;
}
- public function getVisits( $idSite, $period, $date )
+ public function getVisits( $idSite, $period, $date, $segment = false )
{
- return $this->getNumeric( $idSite, $period, $date, 'nb_visits');
+ return $this->getNumeric( $idSite, $period, $date, $segment, 'nb_visits');
}
- public function getUniqueVisitors( $idSite, $period, $date )
+ public function getUniqueVisitors( $idSite, $period, $date, $segment = false )
{
- return $this->getNumeric( $idSite, $period, $date, 'nb_uniq_visitors');
+ return $this->getNumeric( $idSite, $period, $date, $segment, 'nb_uniq_visitors');
}
- public function getActions( $idSite, $period, $date )
+ public function getActions( $idSite, $period, $date, $segment = false )
{
- return $this->getNumeric( $idSite, $period, $date, 'nb_actions');
+ return $this->getNumeric( $idSite, $period, $date, $segment, 'nb_actions');
}
- public function getMaxActions( $idSite, $period, $date )
+ public function getMaxActions( $idSite, $period, $date, $segment = false )
{
- return $this->getNumeric( $idSite, $period, $date, 'max_actions');
+ return $this->getNumeric( $idSite, $period, $date, $segment, 'max_actions');
}
- public function getBounceCount( $idSite, $period, $date )
+ public function getBounceCount( $idSite, $period, $date, $segment = false )
{
- return $this->getNumeric( $idSite, $period, $date, 'bounce_count');
+ return $this->getNumeric( $idSite, $period, $date, $segment, 'bounce_count');
}
- public function getVisitsConverted( $idSite, $period, $date )
+ public function getVisitsConverted( $idSite, $period, $date, $segment = false )
{
- return $this->getNumeric( $idSite, $period, $date, 'nb_visits_converted');
+ return $this->getNumeric( $idSite, $period, $date, $segment, 'nb_visits_converted');
}
- public function getSumVisitsLength( $idSite, $period, $date )
+ public function getSumVisitsLength( $idSite, $period, $date, $segment = false )
{
- return $this->getNumeric( $idSite, $period, $date, 'sum_visit_length');
+ return $this->getNumeric( $idSite, $period, $date, $segment, 'sum_visit_length');
}
- public function getSumVisitsLengthPretty( $idSite, $period, $date )
+ public function getSumVisitsLengthPretty( $idSite, $period, $date, $segment = false )
{
- $table = $this->getSumVisitsLength( $idSite, $period, $date );
+ $table = $this->getSumVisitsLength( $idSite, $period, $date, $segment );
if($table instanceof Piwik_DataTable_Array) {
$table->filter('ColumnCallbackReplace', array(0, array('Piwik', 'getPrettyTimeFromSeconds')));
} else {
diff --git a/tests/core/Database.test.php b/tests/core/Database.test.php
index 952f569227..69726dfe4e 100644
--- a/tests/core/Database.test.php
+++ b/tests/core/Database.test.php
@@ -52,7 +52,6 @@ class Test_Database extends UnitTestCase
Piwik_Option::getInstance()->clearCache();
Piwik_Common::deleteTrackerCache();
Piwik::truncateAllTables();
- Piwik_Archive::clearCache();
}
public function testHelloWorld()
diff --git a/tests/core/Segment.test.php b/tests/core/Segment.test.php
new file mode 100644
index 0000000000..3c2d9304cb
--- /dev/null
+++ b/tests/core/Segment.test.php
@@ -0,0 +1,78 @@
+<?php
+if(!defined('PIWIK_CONFIG_TEST_INCLUDED'))
+{
+ require_once dirname(__FILE__)."/../../tests/config_test.php";
+}
+
+class Test_Piwik_Segment extends UnitTestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+ Piwik::createConfigObject();
+ // Load and install plugins
+ $pluginsManager = Piwik_PluginsManager::getInstance();
+ $pluginsManager->loadPlugins( Zend_Registry::get('config')->Plugins->Plugins->toArray() );
+
+ }
+
+ public function test_()
+ {
+ $tests = array(
+ // Normal segment
+ 'country==France' => array('sql' => ' location_country = ? ', 'bind' => array('France')),
+
+ // unescape the comma please
+ 'country==a\,==' => array('sql' => ' location_country = ? ', 'bind' => array('a,==')),
+
+ // AND, with 2 values rewrites
+ 'country==a;visitorType!=returning;visitorType==new' =>
+ array(
+ 'sql' => ' location_country = ? AND visitor_returning <> ? AND visitor_returning = ? ',
+ 'bind' => array('a', '1', '0')),
+
+ // OR, with 2 value rewrites
+ 'referrerType==search,referrerType==direct' =>
+ array(
+ 'sql'=>' (referer_type = ? OR referer_type = ? )',
+ 'bind' => array( Piwik_Common::REFERER_TYPE_SEARCH_ENGINE,
+ Piwik_Common::REFERER_TYPE_DIRECT_ENTRY
+ )),
+ );
+
+ foreach($tests as $segment => $expected)
+ {
+ $segment = new Piwik_Segment($segment, $idSites = array());
+ $sql = $segment->getSql();
+ $this->assertEqual($sql, $expected, var_export($sql, true));
+
+ // calling twice should give same results
+ $sql = $segment->getSql();
+ $this->assertEqual($sql, $expected, var_export($sql, true));
+
+ $this->assertEqual(strlen($segment->getHash()), 32);
+ }
+ }
+
+ public function test_bogusSegment_ThrowsException()
+ {
+ $tests = array(
+ 'referrerType==not',
+ 'someRandomSegment==not',
+ 'A=B'
+ );
+
+ foreach($tests as $segment)
+ {
+ try {
+ $segment = new Piwik_Segment($segment, $idSites = array());
+ $sql = $segment->getSql();
+ $this->fail();
+ } catch(Exception $e) {
+// var_dump($e->getMessage());
+ $this->pass();
+ }
+ }
+ }
+}
+
diff --git a/tests/core/SegmentExpression.test.php b/tests/core/SegmentExpression.test.php
new file mode 100644
index 0000000000..a0b1462fea
--- /dev/null
+++ b/tests/core/SegmentExpression.test.php
@@ -0,0 +1,89 @@
+<?php
+if(!defined('PIWIK_CONFIG_TEST_INCLUDED'))
+{
+ require_once dirname(__FILE__)."/../../tests/config_test.php";
+}
+
+class Test_Piwik_SegmentExpression extends UnitTestCase
+{
+ public function test_SegmentSql_simpleNoOperation()
+ {
+ $expressionToSql = array(
+ // classic expressions
+ 'A' => " A ",
+ 'A,B' => " (A OR B )",
+ 'A;B' => " A AND B ",
+ 'A;B;C' => " A AND B AND C ",
+ 'A,B;C,D;E,F,G' => " (A OR B) AND (C OR D) AND (E OR F OR G )",
+
+ // unescape the backslash
+ 'A\,B\,C,D' => " (A,B,C OR D )",
+ '\,A' => ' ,A ',
+ // unescape only when it was escaping a known delimiter
+ '\\\A' => ' \\\A ',
+ // unescape at the end
+ '\,\;\A\B,\,C,D\;E\,' => ' (,;\A\B OR ,C OR D;E, )',
+
+ // only replace when a following expression is detected
+ 'A,' => ' A, ',
+ 'A;' => ' A; ',
+ 'A;B;' => ' A AND B; ',
+ 'A,B,' => ' (A OR B, )',
+ );
+ foreach($expressionToSql as $expression => $expectedSql)
+ {
+ $segment = new Piwik_SegmentExpression($expression);
+ $expected = array('sql' => $expectedSql, 'bind' => array());
+ $processed = $segment->getSql();
+ $this->assertEqual($processed, $expected);
+ }
+ }
+
+ public function test_SegmentSql_withOperations()
+ {
+ // Filter expression => SQL string + Bind values
+ $expressionToSql = array(
+ 'A==B' => array('sql' => " A = ? ", 'bind' => array('B')),
+ 'ABCDEF====B===' => array('sql' => " ABCDEF = ? ", 'bind' => array('==B===')),
+ 'A===B;CDEF!=C!=' => array('sql' => " A = ? AND CDEF <> ? ", 'bind' => array('=B', 'C!=' )),
+ 'A==B,C==D' => array('sql' => " (A = ? OR C = ? )", 'bind' => array('B', 'D')),
+ 'A!=B;C==D' => array('sql' => " A <> ? AND C = ? ", 'bind' => array('B', 'D')),
+ 'A!=B;C==D,E!=Hello World!=' => array('sql' => " A <> ? AND (C = ? OR E <> ? )", 'bind' => array('B', 'D', 'Hello World!=')),
+ );
+ foreach($expressionToSql as $expression => $expectedSql)
+ {
+ $segment = new Piwik_SegmentExpression($expression);
+ $segment->parseSubExpressions();
+ $segment->parseSubExpressionsIntoSqlExpressions();
+ $processed = $segment->getSql();
+ $this->assertEqual($processed, $expectedSql, '<br/>'.var_export($processed, true) . "\n *DIFFERENT FROM* ".var_export($expectedSql, true));
+ }
+ }
+
+ public function test_bogusFilters_expectExceptionThrown()
+ {
+ $boguses = array(
+ 'A=B',
+ 'C!D',
+ '',
+ ' ',
+ ',;,',
+ ',',
+ ',,',
+ '===',
+ '!='
+ );
+ foreach($boguses as $bogus)
+ {
+ $segment = new Piwik_SegmentExpression($bogus);
+ try {
+ $segment->parseSubExpressions();
+ $processed = $segment->getSql();
+ $this->fail('expecting exception '.$bogus);
+ } catch(Exception $e) {
+ $this->pass();
+ }
+ }
+ }
+}
+
diff --git a/tests/integration/Integration.php b/tests/integration/Integration.php
index 52d8617ce4..40b93d1421 100644
--- a/tests/integration/Integration.php
+++ b/tests/integration/Integration.php
@@ -337,7 +337,10 @@ abstract class Test_Integration extends Test_Database
'date' => date('Y-m-d', strtotime($dateTime)),
'expanded' => '1',
'piwikUrl' => 'http://example.org/piwik/',
-
+
+ // Used in getKeywordsForPageUrl
+ 'url' => 'http://example.org/store/purchase.htm',
+
// Used in Actions.getPageUrl, .getDownload, etc.
// tied to Main.test.php doTest_oneVisitorTwoVisits
// will need refactoring when these same API functions are tested in a new function
diff --git a/tests/integration/Main.test.php b/tests/integration/Main.test.php
index 208956860d..c06ab60219 100644
--- a/tests/integration/Main.test.php
+++ b/tests/integration/Main.test.php
@@ -145,7 +145,7 @@ class Test_Piwik_Integration_Main extends Test_Integration
* Same as before, but with cookie support, which incurs some slight changes
* in the reporting data (more accurate unique visitor count, better referer tracking for goals, etc.)
*/
- function test_OneVisitorTwoVisits_withCookieSupport()
+ function test_OneVisitorTwoVisits_withCookieSupport()
{
// Tests run in UTC, the Tracker in UTC
$dateTime = '2010-03-06 11:22:33';
@@ -297,10 +297,13 @@ class Test_Piwik_Integration_Main extends Test_Integration
// -
// Test Referer.get* methods in XML
$periods = array('day', 'week', 'month', 'year');
- // Request data for both websites at once
- $idSite = 'all';
// Request data for the last 6 periods
$this->callGetApiCompareOutput(__FUNCTION__, 'xml', $idSite = 'all', $dateTime, $periods, $setDateLastN = true);
+
+ // We also test a single period to check that this use case (Reports per idSite in the response) works
+ $this->setApiToCall(array('VisitsSummary.get', 'Goals.get'));
+ $this->callGetApiCompareOutput(__FUNCTION__ . '_NotLastNPeriods', 'xml', $idSite = 'all', $dateTime, array('day', 'month'), $setDateLastN = false);
+
}
function test_twoVisitsWithCustomVariables()
diff --git a/tests/integration/expected/test_OneVisitorTwoVisits__Actions.getPageUrls_day.xml b/tests/integration/expected/test_OneVisitorTwoVisits__Actions.getPageUrls_day.xml
index 9382774699..10d8d33e82 100644
--- a/tests/integration/expected/test_OneVisitorTwoVisits__Actions.getPageUrls_day.xml
+++ b/tests/integration/expected/test_OneVisitorTwoVisits__Actions.getPageUrls_day.xml
@@ -60,7 +60,7 @@
<exit_nb_visits>1</exit_nb_visits>
<avg_time_on_page>180</avg_time_on_page>
<bounce_rate>0%</bounce_rate>
- <exit_rate>50%</exit_rate>
+ <exit_rate>100%</exit_rate>
<url>http://example.org/index.htm</url>
</row>
</result> \ No newline at end of file
diff --git a/tests/integration/expected/test_OneVisitorTwoVisits__Referers.getKeywordsForPageUrl_day.xml b/tests/integration/expected/test_OneVisitorTwoVisits__Referers.getKeywordsForPageUrl_day.xml
new file mode 100644
index 0000000000..7ade91cdb5
--- /dev/null
+++ b/tests/integration/expected/test_OneVisitorTwoVisits__Referers.getKeywordsForPageUrl_day.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>purchase</row>
+</result> \ No newline at end of file
diff --git a/tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Actions.getPageUrls_day.xml b/tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Actions.getPageUrls_day.xml
index 9382774699..10d8d33e82 100644
--- a/tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Actions.getPageUrls_day.xml
+++ b/tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Actions.getPageUrls_day.xml
@@ -60,7 +60,7 @@
<exit_nb_visits>1</exit_nb_visits>
<avg_time_on_page>180</avg_time_on_page>
<bounce_rate>0%</bounce_rate>
- <exit_rate>50%</exit_rate>
+ <exit_rate>100%</exit_rate>
<url>http://example.org/index.htm</url>
</row>
</result> \ No newline at end of file
diff --git a/tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Referers.getKeywordsForPageUrl_day.xml b/tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Referers.getKeywordsForPageUrl_day.xml
new file mode 100644
index 0000000000..7ade91cdb5
--- /dev/null
+++ b/tests/integration/expected/test_OneVisitorTwoVisits_withCookieSupport__Referers.getKeywordsForPageUrl_day.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>purchase</row>
+</result> \ No newline at end of file
diff --git a/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_day.xml b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_day.xml
new file mode 100644
index 0000000000..1c7f2179e5
--- /dev/null
+++ b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_day.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<results>
+ <result idSite="1" />
+ <result idSite="2" />
+</results> \ No newline at end of file
diff --git a/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_month.xml b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_month.xml
new file mode 100644
index 0000000000..1c7f2179e5
--- /dev/null
+++ b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__Goals.get_month.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<results>
+ <result idSite="1" />
+ <result idSite="2" />
+</results> \ No newline at end of file
diff --git a/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_day.xml b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_day.xml
new file mode 100644
index 0000000000..c01069b78a
--- /dev/null
+++ b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_day.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<results>
+ <result idSite="1">
+ <bounce_count>1</bounce_count>
+ <max_actions>1</max_actions>
+ <nb_actions>1</nb_actions>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <bounce_rate>100%</bounce_rate>
+ <nb_actions_per_visit>1</nb_actions_per_visit>
+ <avg_time_on_site>0</avg_time_on_site>
+ </result>
+ <result idSite="2" />
+</results> \ No newline at end of file
diff --git a/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_month.xml b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_month.xml
new file mode 100644
index 0000000000..e5d1849bd3
--- /dev/null
+++ b/tests/integration/expected/test_TwoVisitors_twoWebsites_differentDays_NotLastNPeriods__VisitsSummary.get_month.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<results>
+ <result idSite="1">
+ <bounce_count>1</bounce_count>
+ <max_actions>4</max_actions>
+ <nb_actions>7</nb_actions>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>3</nb_visits>
+ <sum_visit_length>1260</sum_visit_length>
+ <bounce_rate>33%</bounce_rate>
+ <nb_actions_per_visit>2.3</nb_actions_per_visit>
+ <avg_time_on_site>420</avg_time_on_site>
+ </result>
+ <result idSite="2">
+ <bounce_count>1</bounce_count>
+ <max_actions>1</max_actions>
+ <nb_actions>1</nb_actions>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <bounce_rate>100%</bounce_rate>
+ <nb_actions_per_visit>1</nb_actions_per_visit>
+ <avg_time_on_site>0</avg_time_on_site>
+ </result>
+</results> \ No newline at end of file
diff --git a/tests/integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml b/tests/integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
new file mode 100644
index 0000000000..cab9d52089
--- /dev/null
+++ b/tests/integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Provider</name>
+ <segment>provider</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Country</name>
+ <segment>country</segment>
+ <acceptedValues>de, us, fr, in, es, etc.</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Continent</name>
+ <segment>continent</segment>
+ <acceptedValues>eur, asi, amc, amn, ams, afr, ant, oce</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Server time</name>
+ <segment>visitServerHour</segment>
+ <acceptedValues>0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Local time</name>
+ <segment>visitLocalHour</segment>
+ <acceptedValues>0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Referrers</category>
+ <name>Referrer Type</name>
+ <segment>referrerType</segment>
+ <acceptedValues>direct, search, website, campaign</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Referrers</category>
+ <name>Keyword</name>
+ <segment>referrerKeyword</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Referrers</category>
+ <name>Referrer Name</name>
+ <segment>referrerName</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Referrers</category>
+ <name>Referrer URL</name>
+ <segment>referrerUrl</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Actions</category>
+ <name>Entry Page URL</name>
+ <segment>entryPageUrl</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Actions</category>
+ <name>Entry Page title</name>
+ <segment>entryPageTitle</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Actions</category>
+ <name>Exit Page URL</name>
+ <segment>exitPageUrl</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Actions</category>
+ <name>Exit Page Title</name>
+ <segment>exitPageTitle</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Resolution</name>
+ <segment>resolution</segment>
+ <acceptedValues>1280x1024, 800x600, etc.</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Browser</name>
+ <segment>browserName</segment>
+ <acceptedValues>FF, IE, CH, SF, OP, etc.</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Browser version</name>
+ <segment>browserVersion</segment>
+ <acceptedValues>1.0, 8.0, etc.</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Operating system</name>
+ <segment>operatingSystem</segment>
+ <acceptedValues>WXP, WI7, MAC, LIN, AND, IPD, etc.</acceptedValues>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable name 1</name>
+ <segment>customVariableName1</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable value 1</name>
+ <segment>customVariableValue1</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable name 2</name>
+ <segment>customVariableName2</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable value 2</name>
+ <segment>customVariableValue2</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable name 3</name>
+ <segment>customVariableName3</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable value 3</name>
+ <segment>customVariableValue3</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable name 4</name>
+ <segment>customVariableName4</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable value 4</name>
+ <segment>customVariableValue4</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable name 5</name>
+ <segment>customVariableName5</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Custom Variables</category>
+ <name>Custom Variable value 5</name>
+ <segment>customVariableValue5</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Visitor IP</name>
+ <segment>visitIp</segment>
+ <permission>1</permission>
+ </row>
+ <row>
+ <type>metric</type>
+ <category>Visit</category>
+ <name>Actions</name>
+ <segment>actions</segment>
+ </row>
+ <row>
+ <type>metric</type>
+ <category>Visit</category>
+ <name>Visit Duration (in seconds)</name>
+ <segment>visitDuration</segment>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
+ <name>Visitor type</name>
+ <segment>visitorType</segment>
+ <acceptedValues>new, returning</acceptedValues>
+ </row>
+</result> \ No newline at end of file
diff --git a/tests/integration/expected/test_noVisit__Referers.getKeywordsForPageUrl_day.xml b/tests/integration/expected/test_noVisit__Referers.getKeywordsForPageUrl_day.xml
new file mode 100644
index 0000000000..c234bed59e
--- /dev/null
+++ b/tests/integration/expected/test_noVisit__Referers.getKeywordsForPageUrl_day.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result /> \ No newline at end of file