diff --git a/core/API/Request.php b/core/API/Request.php
index 0fc4d313d00..68cd3fff1d4 100644
--- a/core/API/Request.php
+++ b/core/API/Request.php
@@ -366,7 +366,15 @@ public static function shouldLoadExpanded()
// we have to load all the child subtables.
return Common::getRequestVar('filter_column_recursive', false) !== false
&& Common::getRequestVar('filter_pattern_recursive', false) !== false
- && Common::getRequestVar('flat', false) === false;
+ && !self::shouldLoadFlatten();
+ }
+
+ /**
+ * @return bool
+ */
+ public static function shouldLoadFlatten()
+ {
+ return Common::getRequestVar('flat', false) == 1;
}
/**
diff --git a/core/Archive.php b/core/Archive.php
index db1ca62ded6..3f13396599e 100644
--- a/core/Archive.php
+++ b/core/Archive.php
@@ -192,9 +192,10 @@ protected function __construct(Parameters $params, $forceIndexedBySite = false,
* or date range (ie, 'YYYY-MM-DD,YYYY-MM-DD').
* @param bool|false|string $segment Segment definition or false if no segment should be used. {@link Piwik\Segment}
* @param bool|false|string $_restrictSitesToLogin Used only when running as a scheduled task.
+ * @param bool $skipAggregationOfSubTables Whether the archive, when it is processed, should also aggregate all sub-tables
* @return Archive
*/
- public static function build($idSites, $period, $strDate, $segment = false, $_restrictSitesToLogin = false)
+ public static function build($idSites, $period, $strDate, $segment = false, $_restrictSitesToLogin = false, $skipAggregationOfSubTables = false)
{
$websiteIds = Site::getIdSitesFromIdSitesString($idSites, $_restrictSitesToLogin);
@@ -209,7 +210,7 @@ public static function build($idSites, $period, $strDate, $segment = false, $_re
$segment = new Segment($segment, $websiteIds);
$idSiteIsAll = $idSites == self::REQUEST_ALL_WEBSITES_FLAG;
$isMultipleDate = Period::isMultiplePeriod($strDate, $period);
- return Archive::factory($segment, $allPeriods, $websiteIds, $idSiteIsAll, $isMultipleDate);
+ return Archive::factory($segment, $allPeriods, $websiteIds, $idSiteIsAll, $isMultipleDate, $skipAggregationOfSubTables);
}
/**
@@ -231,9 +232,11 @@ public static function build($idSites, $period, $strDate, $segment = false, $_re
* @param bool $isMultipleDate Whether multiple dates are being queried or not. If true, then
* the result of querying functions will be indexed by period,
* regardless of whether `count($periods) == 1`.
+ * @param bool $skipAggregationOfSubTables Whether the archive should skip aggregation of all sub-tables
+ *
* @return Archive
*/
- public static function factory(Segment $segment, array $periods, array $idSites, $idSiteIsAll = false, $isMultipleDate = false)
+ public static function factory(Segment $segment, array $periods, array $idSites, $idSiteIsAll = false, $isMultipleDate = false, $skipAggregationOfSubTables = false)
{
$forceIndexedBySite = false;
$forceIndexedByDate = false;
@@ -244,7 +247,7 @@ public static function factory(Segment $segment, array $periods, array $idSites,
$forceIndexedByDate = true;
}
- $params = new Parameters($idSites, $periods, $segment);
+ $params = new Parameters($idSites, $periods, $segment, $skipAggregationOfSubTables);
return new Archive($params, $forceIndexedBySite, $forceIndexedByDate);
}
@@ -432,16 +435,21 @@ public function getParams()
* @param string $segment @see {@link build()}
* @param bool $expanded If true, loads all subtables. See {@link getDataTableExpanded()}
* @param int|null $idSubtable See {@link getDataTableExpanded()}
+ * @param bool $skipAggregationOfSubTables Whether or not we should skip the aggregation of all sub-tables and only aggregate parent DataTable.
* @param int|null $depth See {@link getDataTableExpanded()}
* @return DataTable|DataTable\Map See {@link getDataTable()} and
* {@link getDataTableExpanded()} for more
* information
*/
public static function getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded,
- $idSubtable = null, $depth = null)
+ $idSubtable = null, $skipAggregationOfSubTables = false, $depth = null)
{
Piwik::checkUserHasViewAccess($idSite);
- $archive = Archive::build($idSite, $period, $date, $segment);
+
+ if($skipAggregationOfSubTables && ($expanded || $idSubtable)) {
+ throw new \Exception("Not expected to skipAggregationOfSubTables when expanded=1 or idSubtable is set.");
+ }
+ $archive = Archive::build($idSite, $period, $date, $segment, $_restrictSitesToLogin = false, $skipAggregationOfSubTables);
if ($idSubtable === false) {
$idSubtable = null;
}
@@ -620,7 +628,7 @@ private function cacheArchiveIdsAfterLaunching($archiveGroups, $plugins)
private function cacheArchiveIdsWithoutLaunching($plugins)
{
$idarchivesByReport = ArchiveSelector::getArchiveIds(
- $this->params->getIdSites(), $this->params->getPeriods(), $this->params->getSegment(), $plugins);
+ $this->params->getIdSites(), $this->params->getPeriods(), $this->params->getSegment(), $plugins, $this->params->isSkipAggregationOfSubTables());
// initialize archive ID cache for each report
foreach ($plugins as $plugin) {
@@ -644,7 +652,13 @@ private function cacheArchiveIdsWithoutLaunching($plugins)
*/
private function getDoneStringForPlugin($plugin)
{
- return Rules::getDoneStringFlagFor($this->params->getIdSites(), $this->params->getSegment(), $this->getPeriodLabel(), $plugin);
+ return Rules::getDoneStringFlagFor(
+ $this->params->getIdSites(),
+ $this->params->getSegment(),
+ $this->getPeriodLabel(),
+ $plugin,
+ $this->params->isSkipAggregationOfSubTables()
+ );
}
private function getPeriodLabel()
@@ -776,7 +790,7 @@ private static function getPluginForReport($report)
*/
private function prepareArchive(array $archiveGroups, Site $site, Period $period)
{
- $parameters = new ArchiveProcessor\Parameters($site, $period, $this->params->getSegment());
+ $parameters = new ArchiveProcessor\Parameters($site, $period, $this->params->getSegment(), $this->params->isSkipAggregationOfSubTables());
$archiveLoader = new ArchiveProcessor\Loader($parameters);
$periodString = $period->getRangeString();
diff --git a/core/Archive/Parameters.php b/core/Archive/Parameters.php
index 0e2654c0f74..1f700819eee 100644
--- a/core/Archive/Parameters.php
+++ b/core/Archive/Parameters.php
@@ -36,16 +36,22 @@ class Parameters
*/
private $segment;
+ /**
+ * @var bool
+ */
+ private $skipAggregationOfSubTables;
+
public function getSegment()
{
return $this->segment;
}
- public function __construct($idSites, $periods, Segment $segment)
+ public function __construct($idSites, $periods, Segment $segment, $skipAggregationOfSubTables)
{
$this->idSites = $idSites;
$this->periods = $periods;
$this->segment = $segment;
+ $this->skipAggregationOfSubTables = $skipAggregationOfSubTables;
}
public function getPeriods()
@@ -58,5 +64,10 @@ public function getIdSites()
return $this->idSites;
}
+ public function isSkipAggregationOfSubTables()
+ {
+ return $this->skipAggregationOfSubTables;
+ }
+
}
diff --git a/core/ArchiveProcessor.php b/core/ArchiveProcessor.php
index f578673d014..20c4c2df80b 100644
--- a/core/ArchiveProcessor.php
+++ b/core/ArchiveProcessor.php
@@ -199,8 +199,14 @@ public function aggregateDataTableRecords($recordNames,
$table = $this->aggregateDataTableRecord($recordName, $columnsAggregationOperation, $columnsToRenameAfterAggregation);
- $nameToCount[$recordName]['level0'] = $table->getRowsCount();
- $nameToCount[$recordName]['recursive'] = $table->getRowsCountRecursive();
+ $rowsCount = $table->getRowsCount();
+ $nameToCount[$recordName]['level0'] = $rowsCount;
+
+ $rowsCountRecursive = $rowsCount;
+ if($this->isAggregateSubTables()) {
+ $rowsCountRecursive = $table->getRowsCountRecursive();
+ }
+ $nameToCount[$recordName]['recursive'] = $rowsCountRecursive;
$blob = $table->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable, $columnToSortByBeforeTruncation);
Common::destroy($table);
@@ -322,7 +328,15 @@ public function insertBlobRecord($name, $values)
*/
protected function aggregateDataTableRecord($name, $columnsAggregationOperation = null, $columnsToRenameAfterAggregation = null)
{
- $dataTable = $this->getArchive()->getDataTableExpanded($name, $idSubTable = null, $depth = null, $addMetadataSubtableId = false);
+ if($this->isAggregateSubTables()) {
+ // By default we shall aggregate all sub-tables.
+ $dataTable = $this->getArchive()->getDataTableExpanded($name, $idSubTable = null, $depth = null, $addMetadataSubtableId = false);
+ } else {
+ // In some cases (eg. Actions plugin when period=range),
+ // for better performance we will only aggregate the parent table
+ $dataTable = $this->getArchive()->getDataTable($name, $idSubTable = null);
+ }
+
$dataTable = $this->getAggregatedDataTableMap($dataTable, $columnsAggregationOperation);
$this->renameColumnsAfterAggregation($dataTable, $columnsToRenameAfterAggregation);
return $dataTable;
@@ -402,7 +416,7 @@ protected function getAggregatedDataTableMap($data, $columnsAggregationOperation
// as $date => $tableToSum
$this->aggregatedDataTableMapsAsOne($data, $table);
} else {
- $table->addDataTable($data);
+ $table->addDataTable($data, $this->isAggregateSubTables());
}
return $table;
}
@@ -418,7 +432,7 @@ protected function aggregatedDataTableMapsAsOne(Map $map, DataTable $aggregated)
if($tableToAggregate instanceof Map) {
$this->aggregatedDataTableMapsAsOne($tableToAggregate, $aggregated);
} else {
- $aggregated->addDataTable($tableToAggregate);
+ $aggregated->addDataTable($tableToAggregate, $this->isAggregateSubTables());
}
}
}
@@ -430,7 +444,7 @@ protected function renameColumnsAfterAggregation(DataTable $table, $columnsToRen
$columnsToRenameAfterAggregation = self::$columnsToRenameAfterAggregation;
}
foreach ($columnsToRenameAfterAggregation as $oldName => $newName) {
- $table->renameColumn($oldName, $newName);
+ $table->renameColumn($oldName, $newName, $this->isAggregateSubTables());
}
}
@@ -464,4 +478,12 @@ protected function getAggregatedNumericMetrics($columns, $operationToApply)
}
return $metrics;
}
+
+ /**
+ * @return bool
+ */
+ protected function isAggregateSubTables()
+ {
+ return !$this->getParams()->isSkipAggregationOfSubTables();
+ }
}
diff --git a/core/ArchiveProcessor/Loader.php b/core/ArchiveProcessor/Loader.php
index b3ac4cd3f49..03a054a617a 100644
--- a/core/ArchiveProcessor/Loader.php
+++ b/core/ArchiveProcessor/Loader.php
@@ -163,12 +163,8 @@ protected function loadExistingArchiveIdFromDb()
if ($this->isArchivingForcedToTrigger()) {
return $noArchiveFound;
}
- $site = $this->params->getSite();
- $period = $this->params->getPeriod();
- $segment = $this->params->getSegment();
- $requestedPlugin = $this->params->getRequestedPlugin();
- $idAndVisits = ArchiveSelector::getArchiveIdAndVisits($site, $period, $segment, $minDatetimeArchiveProcessedUTC, $requestedPlugin);
+ $idAndVisits = ArchiveSelector::getArchiveIdAndVisits($this->params, $minDatetimeArchiveProcessedUTC);
if (!$idAndVisits) {
return $noArchiveFound;
}
diff --git a/core/ArchiveProcessor/Parameters.php b/core/ArchiveProcessor/Parameters.php
index 1aac335994a..9d9a9088221 100644
--- a/core/ArchiveProcessor/Parameters.php
+++ b/core/ArchiveProcessor/Parameters.php
@@ -48,11 +48,12 @@ class Parameters
*
* @ignore
*/
- public function __construct(Site $site, Period $period, Segment $segment)
+ public function __construct(Site $site, Period $period, Segment $segment, $skipAggregationOfSubTables = false)
{
$this->site = $site;
$this->period = $period;
$this->segment = $segment;
+ $this->skipAggregationOfSubTables = $skipAggregationOfSubTables;
}
/**
@@ -168,6 +169,11 @@ public function isSingleSite()
return count($this->getIdSites()) == 1;
}
+ public function isSkipAggregationOfSubTables()
+ {
+ return $this->skipAggregationOfSubTables;
+ }
+
public function logStatusDebug($isTemporary)
{
$temporary = 'definitive archive';
diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php
index 9aef10302d8..05b37a93af4 100644
--- a/core/ArchiveProcessor/Rules.php
+++ b/core/ArchiveProcessor/Rules.php
@@ -50,10 +50,10 @@ class Rules
* @param string $plugin
* @return string
*/
- public static function getDoneStringFlagFor(array $idSites, $segment, $periodLabel, $plugin)
+ public static function getDoneStringFlagFor(array $idSites, $segment, $periodLabel, $plugin, $isSkipAggregationOfSubTables)
{
if (!self::shouldProcessReportsAllPlugins($idSites, $segment, $periodLabel)) {
- return self::getDoneFlagArchiveContainsOnePlugin($segment, $plugin);
+ return self::getDoneFlagArchiveContainsOnePlugin($segment, $plugin, $isSkipAggregationOfSubTables);
}
return self::getDoneFlagArchiveContainsAllPlugins($segment);
}
@@ -98,9 +98,10 @@ private static function getSegmentsToProcess($idSites)
return $segmentsToProcess;
}
- private static function getDoneFlagArchiveContainsOnePlugin(Segment $segment, $plugin)
+ private static function getDoneFlagArchiveContainsOnePlugin(Segment $segment, $plugin, $isSkipAggregationOfSubTables = false)
{
- return 'done' . $segment->getHash() . '.' . $plugin;
+ $partial = self::isFlagArchivePartial($plugin, $isSkipAggregationOfSubTables);
+ return 'done' . $segment->getHash() . '.' . $plugin . $partial ;
}
private static function getDoneFlagArchiveContainsAllPlugins(Segment $segment)
@@ -108,18 +109,36 @@ private static function getDoneFlagArchiveContainsAllPlugins(Segment $segment)
return 'done' . $segment->getHash();
}
+ /**
+ * @param $plugin
+ * @param $isSkipAggregationOfSubTables
+ * @return string
+ */
+ private static function isFlagArchivePartial($plugin, $isSkipAggregationOfSubTables)
+ {
+ $partialArchive = '';
+ if ($plugin != "VisitsSummary" // VisitsSummary is always called when segmenting and should not have its own .partial archive
+ && $isSkipAggregationOfSubTables
+ ) {
+ $partialArchive = '.partial';
+ }
+ return $partialArchive;
+ }
+
/**
* @param array $plugins
* @param $segment
* @return array
*/
- public static function getDoneFlags(array $plugins, $segment)
+ public static function getDoneFlags(array $plugins, Segment $segment, $isSkipAggregationOfSubTables)
{
$doneFlags = array();
$doneAllPlugins = self::getDoneFlagArchiveContainsAllPlugins($segment);
$doneFlags[$doneAllPlugins] = $doneAllPlugins;
+
+ $plugins = array_unique($plugins);
foreach ($plugins as $plugin) {
- $doneOnePlugin = self::getDoneFlagArchiveContainsOnePlugin($segment, $plugin);
+ $doneOnePlugin = self::getDoneFlagArchiveContainsOnePlugin($segment, $plugin, $isSkipAggregationOfSubTables);
$doneFlags[$plugin] = $doneOnePlugin;
}
return $doneFlags;
diff --git a/core/DataAccess/ArchiveSelector.php b/core/DataAccess/ArchiveSelector.php
index eb994ac7561..4ba9b21b012 100644
--- a/core/DataAccess/ArchiveSelector.php
+++ b/core/DataAccess/ArchiveSelector.php
@@ -42,13 +42,13 @@ class ArchiveSelector
const NB_VISITS_CONVERTED_RECORD_LOOKED_UP = "nb_visits_converted";
- static public function getArchiveIdAndVisits(Site $site, Period $period, Segment $segment, $minDatetimeArchiveProcessedUTC, $requestedPlugin)
+ static public function getArchiveIdAndVisits(ArchiveProcessor\Parameters $params, $minDatetimeArchiveProcessedUTC)
{
- $dateStart = $period->getDateStart();
- $bindSQL = array($site->getId(),
+ $dateStart = $params->getPeriod()->getDateStart();
+ $bindSQL = array($params->getSite()->getId(),
$dateStart->toString('Y-m-d'),
- $period->getDateEnd()->toString('Y-m-d'),
- $period->getId(),
+ $params->getPeriod()->getDateEnd()->toString('Y-m-d'),
+ $params->getPeriod()->getId(),
);
$timeStampWhere = '';
@@ -57,9 +57,12 @@ static public function getArchiveIdAndVisits(Site $site, Period $period, Segment
$bindSQL[] = Date::factory($minDatetimeArchiveProcessedUTC)->getDatetime();
}
- $pluginOrVisitsSummary = array("VisitsSummary", $requestedPlugin);
- $pluginOrVisitsSummary = array_unique($pluginOrVisitsSummary);
- $sqlWhereArchiveName = self::getNameCondition($pluginOrVisitsSummary, $segment);
+ $requestedPlugin = $params->getRequestedPlugin();
+ $segment = $params->getSegment();
+ $isSkipAggregationOfSubTables = $params->isSkipAggregationOfSubTables();
+
+ $plugins = array("VisitsSummary", $requestedPlugin);
+ $sqlWhereArchiveName = self::getNameCondition($plugins, $segment, $isSkipAggregationOfSubTables);
$sqlQuery = " SELECT idarchive, value, name, date1 as startDate
FROM " . ArchiveTableCreator::getNumericTable($dateStart) . "``
@@ -77,8 +80,8 @@ static public function getArchiveIdAndVisits(Site $site, Period $period, Segment
return false;
}
- $idArchive = self::getMostRecentIdArchiveFromResults($segment, $requestedPlugin, $results);
- $idArchiveVisitsSummary = self::getMostRecentIdArchiveFromResults($segment, "VisitsSummary", $results);
+ $idArchive = self::getMostRecentIdArchiveFromResults($segment, $requestedPlugin, $isSkipAggregationOfSubTables, $results);
+ $idArchiveVisitsSummary = self::getMostRecentIdArchiveFromResults($segment, "VisitsSummary", $isSkipAggregationOfSubTables, $results);
list($visits, $visitsConverted) = self::getVisitsMetricsFromResults($idArchive, $idArchiveVisitsSummary, $results);
@@ -116,10 +119,10 @@ protected static function getVisitsMetricsFromResults($idArchive, $idArchiveVisi
return array($visits, $visitsConverted);
}
- protected static function getMostRecentIdArchiveFromResults(Segment $segment, $requestedPlugin, $results)
+ protected static function getMostRecentIdArchiveFromResults(Segment $segment, $requestedPlugin, $isSkipAggregationOfSubTables, $results)
{
$idArchive = false;
- $namesRequestedPlugin = Rules::getDoneFlags(array($requestedPlugin), $segment);
+ $namesRequestedPlugin = Rules::getDoneFlags(array($requestedPlugin), $segment, $isSkipAggregationOfSubTables);
foreach ($results as $result) {
if ($idArchive === false
&& in_array($result['name'], $namesRequestedPlugin)
@@ -138,6 +141,7 @@ protected static function getMostRecentIdArchiveFromResults(Segment $segment, $r
* @param array $periods
* @param Segment $segment
* @param array $plugins List of plugin names for which data is being requested.
+ * @param bool $isSkipAggregationOfSubTables Whether we are selecting an archive that may be partial (no sub-tables)
* @return array Archive IDs are grouped by archive name and period range, ie,
* array(
* 'VisitsSummary.done' => array(
@@ -145,12 +149,12 @@ protected static function getMostRecentIdArchiveFromResults(Segment $segment, $r
* )
* )
*/
- static public function getArchiveIds($siteIds, $periods, $segment, $plugins)
+ static public function getArchiveIds($siteIds, $periods, $segment, $plugins, $isSkipAggregationOfSubTables = false)
{
$getArchiveIdsSql = "SELECT idsite, name, date1, date2, MAX(idarchive) as idarchive
FROM %s
WHERE %s
- AND " . self::getNameCondition($plugins, $segment) . "
+ AND " . self::getNameCondition($plugins, $segment, $isSkipAggregationOfSubTables) . "
AND idsite IN (" . implode(',', $siteIds) . ")
GROUP BY idsite, date1, date2";
@@ -270,20 +274,21 @@ static public function getArchiveData($archiveIds, $recordNames, $archiveDataTyp
*
* @param array $plugins
* @param Segment $segment
+ * @param bool $isSkipAggregationOfSubTables
* @return string
*/
- static private function getNameCondition(array $plugins, $segment)
+ static private function getNameCondition(array $plugins, Segment $segment, $isSkipAggregationOfSubTables)
{
// the flags used to tell how the archiving process for a specific archive was completed,
// if it was completed
- $doneFlags = Rules::getDoneFlags($plugins, $segment);
+ $doneFlags = Rules::getDoneFlags($plugins, $segment, $isSkipAggregationOfSubTables);
$allDoneFlags = "'" . implode("','", $doneFlags) . "'";
// create the SQL to find archives that are DONE
- return "(name IN ($allDoneFlags)) AND " .
+ return "((name IN ($allDoneFlags)) AND " .
" (value = '" . ArchiveWriter::DONE_OK . "' OR " .
- " value = '" . ArchiveWriter::DONE_OK_TEMPORARY . "')";
+ " value = '" . ArchiveWriter::DONE_OK_TEMPORARY . "'))";
}
static public function purgeOutdatedArchives(Date $dateStart)
diff --git a/core/DataAccess/ArchiveWriter.php b/core/DataAccess/ArchiveWriter.php
index bd11053089a..5650a6a828c 100644
--- a/core/DataAccess/ArchiveWriter.php
+++ b/core/DataAccess/ArchiveWriter.php
@@ -66,7 +66,7 @@ public function __construct(ArchiveProcessor\Parameters $params, $isArchiveTempo
$this->segment = $params->getSegment();
$this->period = $params->getPeriod();
$idSites = array($this->idSite);
- $this->doneFlag = Rules::getDoneStringFlagFor($idSites, $this->segment, $this->period->getLabel(), $params->getRequestedPlugin());
+ $this->doneFlag = Rules::getDoneStringFlagFor($idSites, $this->segment, $this->period->getLabel(), $params->getRequestedPlugin(), $params->isSkipAggregationOfSubTables());
$this->isArchiveTemporary = $isArchiveTemporary;
$this->dateStart = $this->period->getDateStart();
diff --git a/core/DataTable.php b/core/DataTable.php
index 9edcaec3732..0f8809821d1 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -469,7 +469,7 @@ public function applyQueuedFilters()
*
* @param \Piwik\DataTable $tableToSum
*/
- public function addDataTable(DataTable $tableToSum)
+ public function addDataTable(DataTable $tableToSum, $doAggregateSubTables = true)
{
if($tableToSum instanceof Simple) {
if($tableToSum->getRowsCount() > 1) {
@@ -479,7 +479,7 @@ public function addDataTable(DataTable $tableToSum)
$this->aggregateRowFromSimpleTable($row);
} else {
foreach ($tableToSum->getRows() as $row) {
- $this->aggregateRowWithLabel($row);
+ $this->aggregateRowWithLabel($row, $doAggregateSubTables);
}
}
}
@@ -891,12 +891,15 @@ public function __sleep()
* @param string $oldName Old column name.
* @param string $newName New column name.
*/
- public function renameColumn($oldName, $newName)
+ public function renameColumn($oldName, $newName, $doRenameColumnsOfSubTables = true)
{
foreach ($this->getRows() as $row) {
$row->renameColumn($oldName, $newName);
- if (($idSubDataTable = $row->getIdSubDataTable()) !== null) {
- Manager::getInstance()->getTable($idSubDataTable)->renameColumn($oldName, $newName);
+
+ if($doRenameColumnsOfSubTables) {
+ if (($idSubDataTable = $row->getIdSubDataTable()) !== null) {
+ Manager::getInstance()->getTable($idSubDataTable)->renameColumn($oldName, $newName);
+ }
}
}
if (!is_null($this->summaryRow)) {
@@ -1582,7 +1585,7 @@ public static function fromSerializedArray($data)
* @param $row
* @throws \Exception
*/
- protected function aggregateRowWithLabel(Row $row)
+ protected function aggregateRowWithLabel(Row $row, $doAggregateSubTables = true)
{
$labelToLookFor = $row->getColumn('label');
if ($labelToLookFor === false) {
@@ -1598,15 +1601,17 @@ protected function aggregateRowWithLabel(Row $row)
} else {
$rowFound->sumRow($row, $copyMeta = true, $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME));
- // if the row to add has a subtable whereas the current row doesn't
- // we simply add it (cloning the subtable)
- // if the row has the subtable already
- // then we have to recursively sum the subtables
- if (($idSubTable = $row->getIdSubDataTable()) !== null) {
- $subTable = Manager::getInstance()->getTable($idSubTable);
- $subTable->metadata[self::COLUMN_AGGREGATION_OPS_METADATA_NAME]
- = $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME);
- $rowFound->sumSubtable($subTable);
+ if($doAggregateSubTables) {
+ // if the row to add has a subtable whereas the current row doesn't
+ // we simply add it (cloning the subtable)
+ // if the row has the subtable already
+ // then we have to recursively sum the subtables
+ if (($idSubTable = $row->getIdSubDataTable()) !== null) {
+ $subTable = Manager::getInstance()->getTable($idSubTable);
+ $subTable->metadata[self::COLUMN_AGGREGATION_OPS_METADATA_NAME]
+ = $this->getMetadata(self::COLUMN_AGGREGATION_OPS_METADATA_NAME);
+ $rowFound->sumSubtable($subTable);
+ }
}
}
}
diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php
index 44deebf1ce1..1d25793433e 100644
--- a/core/Plugin/Manager.php
+++ b/core/Plugin/Manager.php
@@ -669,6 +669,7 @@ private function reloadPlugins()
$this->pluginsToLoad = array_unique($this->pluginsToLoad);
+ $pluginsToPostPendingEventsTo = array();
foreach ($this->pluginsToLoad as $pluginName) {
if (!$this->isPluginLoaded($pluginName)
&& !$this->isPluginThirdPartyAndBogus($pluginName)
@@ -678,9 +679,14 @@ private function reloadPlugins()
continue;
}
- EventDispatcher::getInstance()->postPendingEventsTo($newPlugin);
+ $pluginsToPostPendingEventsTo[] = $newPlugin;
}
}
+
+ // post pending events after all plugins are successfully loaded
+ foreach ($pluginsToPostPendingEventsTo as $plugin) {
+ EventDispatcher::getInstance()->postPendingEventsTo($plugin);
+ }
}
public function getIgnoredBogusPlugins()
diff --git a/core/View.php b/core/View.php
index 8505aafe3fb..4afea486616 100644
--- a/core/View.php
+++ b/core/View.php
@@ -134,9 +134,14 @@ public function __construct($templateFile)
$this->initializeTwig();
$this->piwik_version = Version::VERSION;
- $this->piwikUrl = SettingsPiwik::getPiwikUrl();
$this->userLogin = Piwik::getCurrentUserLogin();
$this->isSuperUser = Access::getInstance()->hasSuperUserAccess(); // TODO: redundancy w/ userIsSuperUser
+
+ try {
+ $this->piwikUrl = SettingsPiwik::getPiwikUrl();
+ } catch (Exception $ex) {
+ // pass (occurs when DB cannot be connected to, perhaps piwik URL cache should be stored in config file...)
+ }
}
/**
@@ -337,8 +342,8 @@ public function assign($var, $value = null)
*/
static public function clearCompiledTemplates()
{
- $view = new View(null);
- $view->twig->clearTemplateCache();
+ $twig = new Twig();
+ $twig->getTwigEnvironment()->clearTemplateCache();
}
/**
diff --git a/libs/PiwikTracker/PiwikTracker.php b/libs/PiwikTracker/PiwikTracker.php
index ab907788992..ec7cdcb4372 100644
--- a/libs/PiwikTracker/PiwikTracker.php
+++ b/libs/PiwikTracker/PiwikTracker.php
@@ -148,6 +148,8 @@ class PiwikTracker
const CVAR_INDEX_ECOMMERCE_ITEM_NAME = 4;
const CVAR_INDEX_ECOMMERCE_ITEM_CATEGORY = 5;
+ const DEFAULT_COOKIE_PATH = '/';
+
/**
* Builds a PiwikTracker object, used to track visits, pages and Goal conversions
* for a specific website, by using the Piwik Tracking API.
@@ -200,7 +202,7 @@ function __construct($idSite, $apiUrl = '')
$this->setNewVisitorId();
$this->configCookiesDisabled = false;
- $this->configCookiePath = '/';
+ $this->configCookiePath = self::DEFAULT_COOKIE_PATH;
$this->configCookieDomain = '';
$this->currentTs = time();
diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php
index ba96ce198be..14efde7db2c 100644
--- a/plugins/Actions/API.php
+++ b/plugins/Actions/API.php
@@ -9,6 +9,7 @@
namespace Piwik\Plugins\Actions;
use Exception;
+use Piwik\API\Request;
use Piwik\Archive;
use Piwik\Common;
@@ -119,8 +120,7 @@ public function get($idSite, $period, $date, $segment = false, $columns = false)
public function getPageUrls($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false,
$depth = false)
{
- $dataTable = Archive::getDataTableFromArchive(
- 'Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $idSubtable, $depth);
+ $dataTable = $this->getDataTableFromArchive('Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $idSubtable, $depth);
$this->filterPageDatatable($dataTable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
@@ -207,7 +207,7 @@ public function getPageUrl($pageUrl, $idSite, $period, $date, $segment = false)
public function getPageTitles($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
{
- $dataTable = Archive::getDataTableFromArchive('Actions_actions', $idSite, $period, $date, $segment, $expanded, $idSubtable);
+ $dataTable = $this->getDataTableFromArchive('Actions_actions', $idSite, $period, $date, $segment, $expanded, $idSubtable);
$this->filterPageDatatable($dataTable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
@@ -248,7 +248,7 @@ public function getPageTitle($pageName, $idSite, $period, $date, $segment = fals
public function getDownloads($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
{
- $dataTable = Archive::getDataTableFromArchive('Actions_downloads', $idSite, $period, $date, $segment, $expanded, $idSubtable);
+ $dataTable = $this->getDataTableFromArchive('Actions_downloads', $idSite, $period, $date, $segment, $expanded, $idSubtable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
@@ -263,7 +263,7 @@ public function getDownload($downloadUrl, $idSite, $period, $date, $segment = fa
public function getOutlinks($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
{
- $dataTable = Archive::getDataTableFromArchive('Actions_outlink', $idSite, $period, $date, $segment, $expanded, $idSubtable);
+ $dataTable = $this->getDataTableFromArchive('Actions_outlink', $idSite, $period, $date, $segment, $expanded, $idSubtable);
$this->filterActionsDataTable($dataTable, $expanded);
return $dataTable;
}
@@ -299,7 +299,7 @@ protected function addPagesPerSearchColumn($dataTable, $columnToRead = 'nb_hits'
protected function getSiteSearchKeywordsRaw($idSite, $period, $date, $segment)
{
- $dataTable = Archive::getDataTableFromArchive('Actions_sitesearch', $idSite, $period, $date, $segment, $expanded = false);
+ $dataTable = $this->getDataTableFromArchive('Actions_sitesearch', $idSite, $period, $date, $segment, $expanded = false);
return $dataTable;
}
@@ -396,7 +396,7 @@ protected function getFilterPageDatatableSearch($callBackParameters, $search, $a
if ($table === false) {
// fetch the data table
- $table = call_user_func_array(array('Piwik\Archive', 'getDataTableFromArchive'), $callBackParameters);
+ $table = call_user_func_array(array($this, 'getDataTableFromArchive'), $callBackParameters);
if ($table instanceof DataTable\Map) {
// search an array of tables, e.g. when using date=last30
@@ -460,7 +460,7 @@ protected function doFilterPageDatatableSearch($callBackParameters, $table, $sea
// match found on this level and more levels remaining: go deeper
$idSubTable = $row->getIdSubDataTable();
$callBackParameters[6] = $idSubTable;
- $table = call_user_func_array(array('Piwik\Archive', 'getDataTableFromArchive'), $callBackParameters);
+ $table = call_user_func_array(array($this, 'getDataTableFromArchive'), $callBackParameters);
return $this->doFilterPageDatatableSearch($callBackParameters, $table, $searchTree);
}
@@ -552,4 +552,16 @@ private function filterNonExitActions($dataTable)
{
$dataTable->filter('ColumnCallbackDeleteRow', array('exit_nb_visits', function ($visits) { return !strlen($visits); }));
}
+
+ protected function getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded = false, $idSubtable = null, $depth = null)
+ {
+ $skipAggregationOfSubTables = false;
+ if($period == 'range'
+ && empty($idSubtable)
+ && empty($expanded)
+ && !Request::shouldLoadFlatten()) {
+ $skipAggregationOfSubTables = true;
+ }
+ return Archive::getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $idSubtable, $skipAggregationOfSubTables, $depth);
+ }
}
diff --git a/tests/PHPUnit/Fixtures/SomeVisitsCustomVariablesCampaignsNotHeuristics.php b/tests/PHPUnit/Fixtures/SomeVisitsCustomVariablesCampaignsNotHeuristics.php
index 71017f77d61..fd587ff2bc4 100644
--- a/tests/PHPUnit/Fixtures/SomeVisitsCustomVariablesCampaignsNotHeuristics.php
+++ b/tests/PHPUnit/Fixtures/SomeVisitsCustomVariablesCampaignsNotHeuristics.php
@@ -123,22 +123,35 @@ private function trackVisits()
self::checkResponse($t4->doTrackPageView('Bonjour le monde'));
}
+ // see updateDomainHash() in piwik.js
+ private function getFirstPartyCookieDomainHash()
+ {
+ $host = \Piwik\Url::getHost();
+ $cookiePath = PiwikTracker::DEFAULT_COOKIE_PATH;
+ return substr(sha1( $host . $cookiePath), 0, 4);
+ }
+
/**
* Test setting/getting the first party cookie via the PHP Tracking Client
* @param $t
*/
private function testFirstPartyCookies(PiwikTracker $t)
{
+ $domainHash = $this->getFirstPartyCookieDomainHash();
+ $idCookieName = '_pk_id_1_' . $domainHash;
+ $refCookieName = '_pk_ref_1_' . $domainHash;
+ $customVarCookieName = '_pk_cvar_1_' . $domainHash;
+
$viewts = '1302307497';
$uuid = 'ca0afe7b6b692ff5';
- $_COOKIE['_pk_id_1_1fff'] = $uuid . '.1302307497.1.' . $viewts . '.1302307497';
- $_COOKIE['_pk_ref_1_1fff'] = '["YEAH","RIGHT!",1302307497,"http://referrer.example.org/page/sub?query=test&test2=test3"]';
- $_COOKIE['_pk_cvar_1_1fff'] = '{"1":["VAR 1 set, var 2 not set","yes"],"3":["var 3 set","yes!!!!"]}';
+ $_COOKIE[$idCookieName] = $uuid . '.1302307497.1.' . $viewts . '.1302307497';
+ $_COOKIE[$refCookieName] = '["YEAH","RIGHT!",1302307497,"http://referrer.example.org/page/sub?query=test&test2=test3"]';
+ $_COOKIE[$customVarCookieName] = '{"1":["VAR 1 set, var 2 not set","yes"],"3":["var 3 set","yes!!!!"]}';
// test loading 'id' cookie
self::assertContains("_viewts=" . $viewts, $t->getUrlTrackPageView());
self::assertEquals($uuid, $t->getVisitorId());
- self::assertEquals($t->getAttributionInfo(), $_COOKIE['_pk_ref_1_1fff']);
+ self::assertEquals($t->getAttributionInfo(), $_COOKIE[$refCookieName]);
self::assertEquals(array("VAR 1 set, var 2 not set", "yes"), $t->getCustomVariable(1));
self::assertFalse($t->getCustomVariable(2));
self::assertEquals(array("var 3 set", "yes!!!!"), $t->getCustomVariable(3));
@@ -147,8 +160,8 @@ private function testFirstPartyCookies(PiwikTracker $t)
self::assertFalse($t->getCustomVariable(6));
self::assertFalse($t->getCustomVariable(-1));
- unset($_COOKIE['_pk_id_1_1fff']);
- unset($_COOKIE['_pk_ref_1_1fff']);
- unset($_COOKIE['_pk_cvar_1_1fff']);
+ unset($_COOKIE[$idCookieName]);
+ unset($_COOKIE[$refCookieName]);
+ unset($_COOKIE[$customVarCookieName]);
}
}
diff --git a/tests/PHPUnit/Fixtures/userAgentParserEnhancedFixtures.yml b/tests/PHPUnit/Fixtures/userAgentParserEnhancedFixtures.yml
index 1cb0a328750..28b4d3d6b66 100644
--- a/tests/PHPUnit/Fixtures/userAgentParserEnhancedFixtures.yml
+++ b/tests/PHPUnit/Fixtures/userAgentParserEnhancedFixtures.yml
@@ -4814,6 +4814,22 @@
model:
os_family: Mac
browser_family: Unknown
+-
+ user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 1091) AppleWebKit/537.36 (KHTML like Gecko) Chrome/33.0.1750.91 Safari/537.36 OPR/20.0.1387.37 (Edition Next)
+ os:
+ name: Mac
+ short_name: MAC
+ version:
+ browser:
+ name: Opera Next
+ short_name: ON
+ version: 20.0
+ device:
+ type: desktop
+ brand:
+ model:
+ os_family: Mac
+ browser_family: Opera
-
user_agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1; en-US) AppleWebKit/9537.73.11 (KHTML, like Gecko) Version/7.0 Safari/537.71 OmniWeb/v624.0'
os:
@@ -5742,6 +5758,22 @@
model:
os_family: Windows
browser_family: Unknown
+-
+ user_agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/33.0.1750.91 Safari/537.36 OPR/20.0.1387.37 (Edition Next-Campaign 21)
+ os:
+ name: Windows 7
+ short_name: WI7
+ version: 7
+ browser:
+ name: Opera Next
+ short_name: ON
+ version: 20.0
+ device:
+ type: desktop
+ brand:
+ model:
+ os_family: Windows
+ browser_family: Opera
-
user_agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36 OPR/18.0.1284.49
os:
@@ -5934,6 +5966,22 @@
model:
os_family: Windows
browser_family: Opera
+-
+ user_agent: Opera/9.80 (Windows NT 6.2; U; Edition Next; ru) Presto/2.11 Version/12.50
+ os:
+ name: Windows 8
+ short_name: WI8
+ version: 8
+ browser:
+ name: Opera Next
+ short_name: ON
+ version: 12.50
+ device:
+ type: desktop
+ brand:
+ model:
+ os_family: Windows
+ browser_family: Opera
-
user_agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68
os:
@@ -6206,6 +6254,22 @@
model:
os_family: Windows
browser_family: Internet Explorer
+-
+ user_agent: Opera/9.80 (Windows NT 6.0; Edition Next) Presto/2.12 Version/12.10
+ os:
+ name: Windows Vista
+ short_name: WVI
+ version: Vista
+ browser:
+ name: Opera Next
+ short_name: ON
+ version: 12.10
+ device:
+ type: desktop
+ brand:
+ model:
+ os_family: Windows
+ browser_family: Opera
-
user_agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Avant Browser; InfoPath.1)
os:
@@ -22189,68 +22253,4 @@
brand: WB
model:
os_family: WebTV
- browser_family: Internet Explorer
--
- user_agent: Opera/9.80 (Windows NT 6.0; Edition Next) Presto/2.12 Version/12.10
- os:
- name: Windows Vista
- short_name: WVI
- version: Vista
- browser:
- name: Opera Next
- short_name: ON
- version: 12.10
- device:
- type: desktop
- brand:
- model:
- os_family: Windows
- browser_family: Opera
--
- user_agent: Opera/9.80 (Windows NT 6.2; U; Edition Next; ru) Presto/2.11 Version/12.50
- os:
- name: Windows 8
- short_name: WI8
- version: 8
- browser:
- name: Opera Next
- short_name: ON
- version: 12.50
- device:
- type: desktop
- brand:
- model:
- os_family: Windows
- browser_family: Opera
--
- user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 1091) AppleWebKit/537.36 (KHTML like Gecko) Chrome/33.0.1750.91 Safari/537.36 OPR/20.0.1387.37 (Edition Next)
- os:
- name: Mac
- short_name: MAC
- version:
- browser:
- name: Opera Next
- short_name: ON
- version: 20.0
- device:
- type: desktop
- brand:
- model:
- os_family: Mac
- browser_family: Opera
--
- user_agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/33.0.1750.91 Safari/537.36 OPR/20.0.1387.37 (Edition Next-Campaign 21)
- os:
- name: Windows 7
- short_name: WI7
- version: 7
- browser:
- name: Opera Next
- short_name: ON
- version: 20.0
- device:
- type: desktop
- brand:
- model:
- os_family: Windows
- browser_family: Opera
\ No newline at end of file
+ browser_family: Internet Explorer
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/OneVisitorOneWebsite_SeveralDaysDateRange_ArchivingTestsTest.php b/tests/PHPUnit/Integration/OneVisitorOneWebsite_SeveralDaysDateRange_ArchivingTestsTest.php
index b751a1b4a58..6c8997b935c 100755
--- a/tests/PHPUnit/Integration/OneVisitorOneWebsite_SeveralDaysDateRange_ArchivingTestsTest.php
+++ b/tests/PHPUnit/Integration/OneVisitorOneWebsite_SeveralDaysDateRange_ArchivingTestsTest.php
@@ -54,18 +54,34 @@ public function getApiForTesting()
for ($i = 0; $i <= 1; $i++) {
foreach ($segments as $segment) {
$result[] = array($apiToCall, array('idSite' => $idSite, 'date' => '2010-12-15,2011-01-15',
- 'periods' => array('range'), 'segment' => $segment));
+ 'periods' => array('range'),
+ 'segment' => $segment,
+ 'otherRequestParameters' => array(
+ 'flat' => '0',
+ 'expanded' => '0'
+ ),
+ ));
}
}
// Testing Date range in January only
// Because of flat=1, this test will archive all sub-tables
$result[] = array('Actions.getPageUrls', array('idSite' => $idSite, 'date' => '2011-01-01,2011-02-01',
- 'periods' => array('range'),
- 'otherRequestParameters' => array(
- 'flat' => '1',
- ),
- 'testSuffix' => '_periodIsRange_flattened_')
+ 'periods' => array('range'),
+ 'otherRequestParameters' => array(
+ 'flat' => '1',
+ 'expanded' => '0'
+ ),
+ 'testSuffix' => '_periodIsRange_flattened_')
+ );
+ // testing the same with expanded=1 should not create new archive records
+ $result[] = array('Actions.getPageUrls', array('idSite' => $idSite, 'date' => '2011-01-01,2011-02-01',
+ 'periods' => array('range'),
+ 'otherRequestParameters' => array(
+ 'flat' => '0',
+ 'expanded' => '1'
+ ),
+ 'testSuffix' => '_periodIsRange_expanded_')
);
return $result;
}
@@ -88,8 +104,7 @@ public function test_checkArchiveRecords_whenPeriodIsRange()
$expectedActionsBlobsWhenFlattened = $expectedActionsBlobs + 3;
$tests = array(
- // TODO Implement fix, then remove the +3 below
- 'archive_blob_2010_12' => ( ($expectedActionsBlobs+3) /*Actions*/
+ 'archive_blob_2010_12' => ( $expectedActionsBlobs /*Actions*/
+ 8 /* UserSettings */
+ 2 /* VisitTime */) * 3,
@@ -137,12 +152,31 @@ public function test_checkArchiveRecords_whenPeriodIsRange()
$countBlobs = Db::get()->fetchOne($sql);
if($expectedRows != $countBlobs) {
- var_export(Db::get()->fetchAll("SELECT * FROM " . Common::prefixTable($table). " WHERE period = " . Piwik::$idPeriods['range'] . " ORDER BY idarchive ASC"));
+ $this->printDebugWhenTestFails($table);
}
$this->assertEquals($expectedRows, $countBlobs, "$table expected $expectedRows, got $countBlobs");
}
}
+ /**
+ * @param $table
+ */
+ protected function printDebugWhenTestFails($table)
+ {
+ $data = Db::get()->fetchAll("SELECT * FROM " . Common::prefixTable($table) . " WHERE period = " . Piwik::$idPeriods['range'] . " ORDER BY idarchive ASC");
+ var_export($data);
+
+ $idArchives = array();
+ foreach ($data as $row) {
+ $idArchives[] = $row['idarchive'];
+ }
+ $idArchives = array_unique($idArchives);
+ foreach ($idArchives as $idArchive) {
+ $numericTable = str_replace("blob", "numeric", Common::prefixTable($table));
+ var_export(Db::get()->fetchAll("SELECT idarchive, name FROM " . $numericTable . " WHERE idarchive = ? AND name LIKE 'done%' LIMIT 1 ", $idArchive));
+ }
+ }
+
}
Test_Piwik_Integration_OneVisitorOneWebsite_SeveralDaysDateRange_ArchivingTests::$fixture
diff --git a/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange__Actions.getPageUrls_range.xml b/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange__Actions.getPageUrls_range.xml
index c9d04097521..62ee4df14dc 100644
--- a/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange__Actions.getPageUrls_range.xml
+++ b/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange__Actions.getPageUrls_range.xml
@@ -43,44 +43,5 @@
0
0%
100%
-
-
-
- 3
- 3
- 0
- 3
- 0
- 0%
- 100%
-
-
-
- 3
- 3
- 0
- 3
- 0
- 0%
- 100%
-
-
-
- 3
- 3
- 0
- 3
- 2
- 2
- 0
- 0%
- 100%
- http://example.org/sub1/sub2/sub3/news
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange_periodIsRange_flattened___Actions.getPageUrls_range.xml b/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange_periodIsRange_flattened___Actions.getPageUrls_range.xml
index bd8b87ef40d..1f11de6d952 100644
--- a/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange_periodIsRange_flattened___Actions.getPageUrls_range.xml
+++ b/tests/PHPUnit/Integration/expected/test_oneVisitor_oneWebsite_severalDays_DateRange_periodIsRange_flattened___Actions.getPageUrls_range.xml
@@ -34,4 +34,17 @@
100%
http://example.org/news
+
+
+ 2
+ 2
+ 0
+ 2
+ 2
+ 2
+ 0
+ 0%
+ 100%
+ http://example.org/sub1/sub2/sub3/news
+
\ No newline at end of file
diff --git a/tests/PHPUnit/UI b/tests/PHPUnit/UI
index f18a9102aa4..f744d26a33b 160000
--- a/tests/PHPUnit/UI
+++ b/tests/PHPUnit/UI
@@ -1 +1 @@
-Subproject commit f18a9102aa434db63bfdd2c6d47d9ee4fca77581
+Subproject commit f744d26a33b64570a039d65c23c7dfaaff1a245a
diff --git a/tests/lib/screenshot-testing/support/app.js b/tests/lib/screenshot-testing/support/app.js
index ee9ad303140..8a67e68ed6f 100644
--- a/tests/lib/screenshot-testing/support/app.js
+++ b/tests/lib/screenshot-testing/support/app.js
@@ -105,7 +105,7 @@ Application.prototype.loadTestModules = function () {
// configure suites (auto-add fixture setup/teardown)
mocha.suite.suites.forEach(function (suite) {
- var fixture = suite.fixture || 'UITestFixture';
+ var fixture = typeof suite.fixture === 'undefined' ? 'UITestFixture' : suite.fixture;
suite.beforeAll(function (done) {
testEnvironment.setupFixture(fixture, done);
@@ -115,6 +115,11 @@ Application.prototype.loadTestModules = function () {
suite._beforeAll.unshift(suite._beforeAll.pop());
suite.afterAll(function (done) {
+ if (!fixture) {
+ done();
+ return;
+ }
+
testEnvironment.teardownFixture(fixture, done);
});
});
diff --git a/tests/lib/screenshot-testing/support/setupDatabase.php b/tests/lib/screenshot-testing/support/setupDatabase.php
index e91e4ffd16f..e4efccb0e74 100644
--- a/tests/lib/screenshot-testing/support/setupDatabase.php
+++ b/tests/lib/screenshot-testing/support/setupDatabase.php
@@ -20,19 +20,21 @@
require_once "PHPUnit/Autoload.php";
require_once dirname(__FILE__) . "/../../../PHPUnit/bootstrap.php";
-if (!class_exists($fixtureClass)) {
- $fixtureClass = "Piwik\\Tests\\Fixtures\\$fixtureClass";
-}
+if (!empty($fixtureClass)) {
+ if (!class_exists($fixtureClass)) {
+ $fixtureClass = "Piwik\\Tests\\Fixtures\\$fixtureClass";
+ }
-$fixture = new $fixtureClass();
-if (in_array("--persist-fixture-data", $argv)) {
- $fixture->persistFixtureData = true;
-}
-if (in_array("--drop", $argv)) {
- $fixture->resetPersistedFixture = true;
+ $fixture = new $fixtureClass();
+ if (in_array("--persist-fixture-data", $argv)) {
+ $fixture->persistFixtureData = true;
+ }
+ if (in_array("--drop", $argv)) {
+ $fixture->resetPersistedFixture = true;
+ }
+ $fixture->printToScreen = true;
+ $fixture->performSetUp("");
}
-$fixture->printToScreen = true;
-$fixture->performSetUp("");
// make sure symbolic links exist (phantomjs doesn't support symlink-ing yet)
foreach (array('libs', 'plugins', 'tests', 'piwik.js') as $linkName) {
diff --git a/tests/lib/screenshot-testing/support/test-environment.js b/tests/lib/screenshot-testing/support/test-environment.js
index c371d444e31..7096b2af26b 100644
--- a/tests/lib/screenshot-testing/support/test-environment.js
+++ b/tests/lib/screenshot-testing/support/test-environment.js
@@ -88,7 +88,7 @@ TestingEnvironment.prototype.setupFixture = function (fixtureClass, done) {
console.log(" Setting up fixture " + fixtureClass + "...");
var setupFile = path.join("./support", "setupDatabase.php"),
- processArgs = [setupFile, "--server=" + JSON.stringify(config.phpServer), "--fixture=" + fixtureClass];
+ processArgs = [setupFile, "--server=" + JSON.stringify(config.phpServer), "--fixture=" + (fixtureClass || "")];
if (options['persist-fixture-data']) {
processArgs.push('--persist-fixture-data');