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:
authorsgiehl <stefan@piwik.org>2014-04-03 16:45:54 +0400
committersgiehl <stefan@piwik.org>2014-04-03 16:45:54 +0400
commite380ce2246173ab0dda603dc2eb515711ea2e34b (patch)
tree93e92fc7ed566053cda375974de74cdba4744360
parent7a98becbec6bf32038549c879b4f6cfda3a7b77d (diff)
parent644b63fd6035fd8d0b113e8ce71629af0378e738 (diff)
Merge branch 'master' into DeviceDetectorIntegration
-rw-r--r--config/global.ini.php4
-rw-r--r--core/API/ResponseBuilder.php8
-rw-r--r--core/Access.php35
-rw-r--r--core/ArchiveProcessor/Rules.php2
-rw-r--r--core/Console.php6
-rw-r--r--core/CronArchive.php10
-rw-r--r--core/Db.php18
-rw-r--r--core/Db/Schema/Mysql.php31
-rw-r--r--core/Menu/MenuAbstract.php11
-rw-r--r--core/Piwik.php78
-rw-r--r--core/Plugin/Manager.php11
-rw-r--r--core/Tracker.php4
-rw-r--r--core/Tracker/Action.php3
-rw-r--r--core/Tracker/GoalManager.php10
-rw-r--r--core/Tracker/Request.php6
-rw-r--r--core/Tracker/Visit.php15
-rw-r--r--core/Updater.php45
-rw-r--r--core/Updates/2.1.1-b11.php127
-rw-r--r--core/Version.php2
-rw-r--r--core/testMinimumPhpVersion.php3
-rw-r--r--lang/en.json2
-rw-r--r--piwik.php3
-rw-r--r--plugins/API/Controller.php5
-rw-r--r--plugins/CoreAdminHome/Controller.php2
-rw-r--r--plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js249
-rw-r--r--plugins/CoreAdminHome/templates/trackingCodeGenerator.twig2
-rw-r--r--plugins/CoreConsole/Commands/CoreArchiver.php42
-rw-r--r--plugins/CoreConsole/Commands/SyncUITestScreenshots.php4
-rw-r--r--plugins/CoreUpdater/Commands/Update.php3
m---------plugins/CustomAlerts0
-rw-r--r--plugins/CustomVariables/Archiver.php3
-rw-r--r--plugins/CustomVariables/Commands/Info.php69
-rw-r--r--plugins/CustomVariables/Commands/SetNumberOfCustomVariables.php209
-rw-r--r--plugins/CustomVariables/CustomVariables.php51
-rw-r--r--plugins/CustomVariables/Model.php170
-rw-r--r--plugins/CustomVariables/tests/CustomVariablesTest.php43
-rw-r--r--plugins/CustomVariables/tests/ModelTest.php154
-rw-r--r--plugins/Dashboard/javascripts/dashboardObject.js1
-rw-r--r--plugins/Goals/Controller.php2
-rw-r--r--plugins/Live/Visitor.php17
-rw-r--r--plugins/SitesManager/API.php53
-rw-r--r--plugins/VisitFrequency/API.php123
-rw-r--r--plugins/VisitFrequency/Archiver.php131
-rw-r--r--plugins/Zeitgeist/templates/javascriptCode.tpl1
-rw-r--r--tests/PHPUnit/Core/DeprecatedMethodsTest.php3
-rw-r--r--tests/PHPUnit/Core/ReleaseCheckListTest.php22
-rw-r--r--tests/PHPUnit/FakeAccess.php25
-rw-r--r--tests/PHPUnit/Integration/Core/DbTest.php32
-rw-r--r--tests/PHPUnit/Integration/Core/LogTest.php2
-rw-r--r--tests/PHPUnit/Integration/Core/PiwikTest.php1
-rw-r--r--tests/PHPUnit/Integration/Core/SegmentTest.php (renamed from tests/PHPUnit/Core/SegmentTest.php)2
-rw-r--r--tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referrers.getCleanKeyword.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_day.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_month.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_day.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_month.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getRowEvolution_day.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml1
-rw-r--r--tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_Metadata_Goals.Get_NotExistingGoal__API.getProcessedReport_day.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_day.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_week.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_day.xml2
-rw-r--r--tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_week.xml2
m---------tests/PHPUnit/UI0
64 files changed, 1224 insertions, 654 deletions
diff --git a/config/global.ini.php b/config/global.ini.php
index 78204437b4..f98d57588c 100644
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -86,6 +86,10 @@ tracker_always_new_visitor = 0
; Allow automatic upgrades to Beta or RC releases
allow_upgrades_to_beta = 0
+; Set to 1 by default. If you set to 0, the standalone plugins (with their own git repositories)
+; will not be loaded when executing tests.
+enable_load_standalone_plugins_during_tests = 1
+
[General]
; the following settings control whether Unique Visitors will be processed for different period types.
; year and range periods are disabled by default, to ensure optimal performance for high traffic Piwik instances
diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php
index 55fce0d0d5..692a2ceb71 100644
--- a/core/API/ResponseBuilder.php
+++ b/core/API/ResponseBuilder.php
@@ -22,8 +22,6 @@ use Piwik\DataTable;
*/
class ResponseBuilder
{
- const DISPLAY_BACKTRACE_DEBUG = false;
-
private $request = null;
private $outputFormat = null;
@@ -162,12 +160,10 @@ class ResponseBuilder
{
// If we are in tests, show full backtrace
if (defined('PIWIK_PATH_TEST_TO_ROOT')) {
- if (self::DISPLAY_BACKTRACE_DEBUG
- || \Piwik_ShouldPrintBackTraceWithMessage()
- ) {
+ if (\Piwik_ShouldPrintBackTraceWithMessage()) {
$message = $e->getMessage() . " in \n " . $e->getFile() . ":" . $e->getLine() . " \n " . $e->getTraceAsString();
} else {
- $message = $e->getMessage() . "\n \n --> To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in " . basename(__FILE__);
+ $message = $e->getMessage() . "\n \n --> To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php";
}
return new Exception($message);
}
diff --git a/core/Access.php b/core/Access.php
index a7b4d7178e..55335385d0 100644
--- a/core/Access.php
+++ b/core/Access.php
@@ -246,15 +246,6 @@ class Access
}
/**
- * @see Access::setSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- public function setSuperUser($bool = true)
- {
- self::setSuperUserAccess($bool);
- }
-
- /**
* Returns true if the current user is logged in as the Super User
*
* @return bool
@@ -265,15 +256,6 @@ class Access
}
/**
- * @see Access::hasSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- public function isSuperUser()
- {
- return $this->hasSuperUserAccess();
- }
-
- /**
* Returns the current user login
*
* @return string|null
@@ -315,14 +297,6 @@ class Access
}
/**
- * @deprecated deprecated since version 2.0.4
- */
- public function getSuperUserLogin()
- {
- return $this->getAnySuperUserAccessLogin();
- }
-
- /**
* Returns an array of ID sites for which the user has at least a VIEW access.
* Which means VIEW or ADMIN or SUPERUSER.
*
@@ -378,15 +352,6 @@ class Access
}
/**
- * @see Access::checkUserHasSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- public function checkUserIsSuperUser()
- {
- self::checkUserHasSuperUserAccess();
- }
-
- /**
* If the user doesn't have an ADMIN access for at least one website, throws an exception
*
* @throws \Piwik\NoAccessException
diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php
index 02a8357ac6..13f2a34610 100644
--- a/core/ArchiveProcessor/Rules.php
+++ b/core/ArchiveProcessor/Rules.php
@@ -98,7 +98,7 @@ class Rules
return $segmentsToProcess;
}
- private static function getDoneFlagArchiveContainsOnePlugin(Segment $segment, $plugin, $isSkipAggregationOfSubTables = false)
+ public static function getDoneFlagArchiveContainsOnePlugin(Segment $segment, $plugin, $isSkipAggregationOfSubTables = false)
{
$partial = self::isFlagArchivePartial($plugin, $isSkipAggregationOfSubTables);
return 'done' . $segment->getHash() . '.' . $plugin . $partial ;
diff --git a/core/Console.php b/core/Console.php
index e6d1f91397..f2db14934f 100644
--- a/core/Console.php
+++ b/core/Console.php
@@ -119,9 +119,9 @@ class Console extends Application
$commands = array(
'Piwik\CliMulti\RequestCommand'
);
-
- if (class_exists('Piwik\Plugins\CloudAdmin\CloudAdmin')) {
- $extra = new \Piwik\Plugins\CloudAdmin\CloudAdmin();
+
+ if (class_exists('Piwik\Plugins\EnterpriseAdmin\EnterpriseAdmin')) {
+ $extra = new \Piwik\Plugins\EnterpriseAdmin\EnterpriseAdmin();
$extra->addConsoleCommands($commands);
}
return $commands;
diff --git a/core/CronArchive.php b/core/CronArchive.php
index 0f3e877de5..f77ae23983 100644
--- a/core/CronArchive.php
+++ b/core/CronArchive.php
@@ -540,7 +540,7 @@ class CronArchive
$url .= self::APPEND_TO_API_REQUEST;
- $visitsInLastPeriods = 0;
+ $visitsInLastPeriods = $visitsLastPeriod = 0;
$success = true;
$urls = array();
@@ -1122,12 +1122,18 @@ class CronArchive
private function getVisitsLastPeriodFromApiResponse($stats)
{
+ if(empty($stats)) {
+ return 0;
+ }
$today = end($stats);
return $today['nb_visits'];
}
private function getVisitsFromApiResponse($stats)
{
+ if(empty($stats)) {
+ return 0;
+ }
$visits = 0;
foreach($stats as $metrics) {
if(empty($metrics['nb_visits'])) {
@@ -1200,7 +1206,7 @@ class CronArchiveFatalException extends Exception
$this->fullOutput = $fullOutput;
}
- public function logAndExit($cronArchiver)
+ public function logAndExit(CronArchive$cronArchiver)
{
if ($cronArchiver->isCoreInited()) {
$cronArchiver->logError($this->getMessage());
diff --git a/core/Db.php b/core/Db.php
index f099d01409..5a65c8451b 100644
--- a/core/Db.php
+++ b/core/Db.php
@@ -331,6 +331,24 @@ class Db
}
/**
+ * Get columns information from table
+ *
+ * @param string|array $table The name of the table you want to get the columns definition for.
+ * @return \Zend_Db_Statement
+ */
+ static public function getColumnNamesFromTable($table)
+ {
+ $columns = self::fetchAll("SHOW COLUMNS FROM " . $table);
+
+ $columnNames = array();
+ foreach ($columns as $column) {
+ $columnNames[] = $column['Field'];
+ }
+
+ return $columnNames;
+ }
+
+ /**
* Locks the supplied table or tables.
*
* **NOTE:** Piwik does not require the `LOCK TABLES` privilege to be available. Piwik
diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php
index fa326a9dc4..34c3764f2f 100644
--- a/core/Db/Schema/Mysql.php
+++ b/core/Db/Schema/Mysql.php
@@ -192,16 +192,6 @@ class Mysql implements SchemaInterface
location_city varchar(255) DEFAULT NULL,
location_latitude float(10, 6) DEFAULT NULL,
location_longitude float(10, 6) DEFAULT NULL,
- custom_var_k1 VARCHAR(200) DEFAULT NULL,
- custom_var_v1 VARCHAR(200) DEFAULT NULL,
- custom_var_k2 VARCHAR(200) DEFAULT NULL,
- custom_var_v2 VARCHAR(200) DEFAULT NULL,
- custom_var_k3 VARCHAR(200) DEFAULT NULL,
- custom_var_v3 VARCHAR(200) DEFAULT NULL,
- custom_var_k4 VARCHAR(200) DEFAULT NULL,
- custom_var_v4 VARCHAR(200) DEFAULT NULL,
- custom_var_k5 VARCHAR(200) DEFAULT NULL,
- custom_var_v5 VARCHAR(200) DEFAULT NULL,
PRIMARY KEY(idvisit),
INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time),
INDEX index_idsite_datetime (idsite, visit_last_action_time),
@@ -264,16 +254,6 @@ class Mysql implements SchemaInterface
revenue_shipping float default NULL,
revenue_discount float default NULL,
- custom_var_k1 VARCHAR(200) DEFAULT NULL,
- custom_var_v1 VARCHAR(200) DEFAULT NULL,
- custom_var_k2 VARCHAR(200) DEFAULT NULL,
- custom_var_v2 VARCHAR(200) DEFAULT NULL,
- custom_var_k3 VARCHAR(200) DEFAULT NULL,
- custom_var_v3 VARCHAR(200) DEFAULT NULL,
- custom_var_k4 VARCHAR(200) DEFAULT NULL,
- custom_var_v4 VARCHAR(200) DEFAULT NULL,
- custom_var_k5 VARCHAR(200) DEFAULT NULL,
- custom_var_v5 VARCHAR(200) DEFAULT NULL,
PRIMARY KEY (idvisit, idgoal, buster),
UNIQUE KEY unique_idsite_idorder (idsite, idorder),
INDEX index_idsite_datetime ( idsite, server_time )
@@ -293,16 +273,7 @@ class Mysql implements SchemaInterface
idaction_event_category INTEGER(10) UNSIGNED DEFAULT NULL,
idaction_event_action INTEGER(10) UNSIGNED DEFAULT NULL,
time_spent_ref_action INTEGER(10) UNSIGNED NOT NULL,
- custom_var_k1 VARCHAR(200) DEFAULT NULL,
- custom_var_v1 VARCHAR(200) DEFAULT NULL,
- custom_var_k2 VARCHAR(200) DEFAULT NULL,
- custom_var_v2 VARCHAR(200) DEFAULT NULL,
- custom_var_k3 VARCHAR(200) DEFAULT NULL,
- custom_var_v3 VARCHAR(200) DEFAULT NULL,
- custom_var_k4 VARCHAR(200) DEFAULT NULL,
- custom_var_v4 VARCHAR(200) DEFAULT NULL,
- custom_var_k5 VARCHAR(200) DEFAULT NULL,
- custom_var_v5 VARCHAR(200) DEFAULT NULL,
+
custom_float FLOAT NULL DEFAULT NULL,
PRIMARY KEY(idlink_va),
INDEX index_idvisit(idvisit),
diff --git a/core/Menu/MenuAbstract.php b/core/Menu/MenuAbstract.php
index 1d35509e36..781aed7b81 100644
--- a/core/Menu/MenuAbstract.php
+++ b/core/Menu/MenuAbstract.php
@@ -163,10 +163,17 @@ abstract class MenuAbstract extends Singleton
$mainMenuToEdit = $edit[0];
$subMenuToEdit = $edit[1];
$newUrl = $edit[2];
- if (!isset($this->menu[$mainMenuToEdit][$subMenuToEdit])) {
+
+ if ($subMenuToEdit === null) {
+ $menuDataToEdit = @$this->menu[$mainMenuToEdit];
+ } else {
+ $menuDataToEdit = @$this->menu[$mainMenuToEdit][$subMenuToEdit];
+ }
+
+ if (empty($menuDataToEdit)) {
$this->buildMenuItem($mainMenuToEdit, $subMenuToEdit, $newUrl);
} else {
- $this->menu[$mainMenuToEdit][$subMenuToEdit]['_url'] = $newUrl;
+ $menuDataToEdit['_url'] = $newUrl;
}
}
}
diff --git a/core/Piwik.php b/core/Piwik.php
index 54d7e54375..6c47070734 100644
--- a/core/Piwik.php
+++ b/core/Piwik.php
@@ -186,16 +186,16 @@ class Piwik
* this event to customise the JavaScript tracking code that is displayed to the
* user.
*
- * @param array $codeImpl An array containing snippets of code that the event handler
- * can modify. Will contain the following elements:
+ * @param array &$codeImpl An array containing snippets of code that the event handler
+ * can modify. Will contain the following elements:
*
- * - **idSite**: The ID of the site being tracked.
- * - **piwikUrl**: The tracker URL to use.
- * - **options**: A string of JavaScript code that customises
- * the JavaScript tracker.
+ * - **idSite**: The ID of the site being tracked.
+ * - **piwikUrl**: The tracker URL to use.
+ * - **options**: A string of JavaScript code that customises
+ * the JavaScript tracker.
*
- * The **httpsPiwikUrl** element can be set if the HTTPS
- * domain is different from the normal domain.
+ * The **httpsPiwikUrl** element can be set if the HTTPS
+ * domain is different from the normal domain.
* @param array $parameters The parameters supplied to the `Piwik::getJavascriptCode()`.
*/
self::postEvent('Piwik.getJavascriptCode', array(&$codeImpl, $parameters));
@@ -258,22 +258,6 @@ class Piwik
}
/**
- * @deprecated deprecated since version 2.0.4
- */
- static public function getSuperUserLogin()
- {
- return Access::getInstance()->getSuperUserLogin();
- }
-
- /**
- * @deprecated deprecated since version 2.0.4
- */
- static public function getSuperUserEmail()
- {
- return '';
- }
-
- /**
* Get a list of all email addresses having Super User access.
*
* @return array
@@ -336,24 +320,6 @@ class Piwik
}
/**
- * @see Piwik::hasUserSuperUserAccessOrIsTheUser()
- * @deprecated deprecated since version 2.0.4
- */
- static public function isUserIsSuperUserOrTheUser($theUser)
- {
- return self::hasUserSuperUserAccessOrIsTheUser($theUser);
- }
-
- /**
- * @see Piwik::checkUserHasSuperUserAccessOrIsTheUser()
- * @deprecated deprecated since version 2.0.4
- */
- static public function checkUserIsSuperUserOrTheUser($theUser)
- {
- self::checkUserHasSuperUserAccessOrIsTheUser($theUser);
- }
-
- /**
* Check that the current user is either the specified user or the superuser.
*
* @param string $theUser A username.
@@ -404,14 +370,6 @@ class Piwik
return false;
}
- /**
- * @see Piwik::hasUserSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- static public function isUserIsSuperUser()
- {
- return self::hasUserSuperUserAccess();
- }
/**
* Returns true if the current user has Super User access.
@@ -465,24 +423,6 @@ class Piwik
}
/**
- * @see Piwik::setUserHasSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- static public function setUserIsSuperUser($bool = true)
- {
- self::setUserHasSuperUserAccess($bool);
- }
-
- /**
- * @see Piwik::checkUserHasSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- static public function checkUserIsSuperUser()
- {
- self::checkUserHasSuperUserAccess();
- }
-
- /**
* Check that the current user has superuser access.
*
* @throws Exception if the current user is not the superuser.
@@ -889,7 +829,7 @@ class Piwik
}
$options = '';
if ($mergeSubdomains && !empty($websiteHosts)) {
- $options .= PHP_EOL . ' _paq.push(["setCookieDomain", "*.' . $websiteHosts[0] . '"]);' . PHP_EOL;
+ $options .= ' _paq.push(["setCookieDomain", "*.' . $websiteHosts[0] . '"]);' . PHP_EOL;
}
if ($mergeAliasUrls && !empty($websiteHosts)) {
$urls = '["*.' . implode('","*.', $websiteHosts) . '"]';
diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php
index 4bd1cc1d8c..825c6fcaa4 100644
--- a/core/Plugin/Manager.php
+++ b/core/Plugin/Manager.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugin;
use Piwik\Common;
use Piwik\Config as PiwikConfig;
+use Piwik\Config;
use Piwik\EventDispatcher;
use Piwik\Filesystem;
use Piwik\Option;
@@ -101,7 +102,15 @@ class Manager extends Singleton
// Also load plugins which are Git repositories (eg. being developed)
$isPluginHasGitRepository = file_exists( PIWIK_INCLUDE_PATH . '/plugins/' . $plugin . '/.git/config');
- $loadPlugin = $isPluginBundledWithCore || $isPluginOfficiallySupported || $isPluginHasGitRepository;
+ $loadPlugin = $isPluginBundledWithCore || $isPluginOfficiallySupported;
+
+ $loadStandalonePluginsDuringTests = Config::getInstance()->Debug['enable_load_standalone_plugins_during_tests'];
+
+ if($loadStandalonePluginsDuringTests) {
+ $loadPlugin = $loadPlugin || $isPluginHasGitRepository;
+ } else {
+ $loadPlugin = $loadPlugin && !$isPluginHasGitRepository;
+ }
// Do not enable other Themes
$disabledThemes = $this->coreThemesDisabledByDefault;
diff --git a/core/Tracker.php b/core/Tracker.php
index 05deb9a2aa..17265e76ed 100644
--- a/core/Tracker.php
+++ b/core/Tracker.php
@@ -43,10 +43,6 @@ class Tracker
const LENGTH_HEX_ID_STRING = 16;
const LENGTH_BINARY_ID = 8;
- // These are also hardcoded in the Javascript
- const MAX_CUSTOM_VARIABLES = 5;
- const MAX_LENGTH_CUSTOM_VARIABLE = 200;
-
static protected $forcedDateTime = null;
static protected $forcedIpString = null;
static protected $forcedVisitorId = null;
diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php
index aa940151d7..a1d879b52e 100644
--- a/core/Tracker/Action.php
+++ b/core/Tracker/Action.php
@@ -190,9 +190,6 @@ abstract class Action
public function writeDebugInfo()
{
- if (!isset($GLOBALS['PIWIK_TRACKER_DEBUG']) || !$GLOBALS['PIWIK_TRACKER_DEBUG']) {
- return false;
- }
$type = self::getTypeAsString($this->getActionType());
Common::printDebug("Action is a $type,
Action name = " . $this->getActionName() . ",
diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php
index 939565e7fe..daa88bd7b9 100644
--- a/core/Tracker/GoalManager.php
+++ b/core/Tracker/GoalManager.php
@@ -11,8 +11,8 @@ namespace Piwik\Tracker;
use Exception;
use Piwik\Common;
use Piwik\Config;
-use Piwik\Log;
use Piwik\Piwik;
+use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Tracker;
/**
@@ -227,7 +227,11 @@ class GoalManager
}
// Copy Custom Variables from Visit row to the Goal conversion
- for ($i = 1; $i <= Tracker::MAX_CUSTOM_VARIABLES; $i++) {
+ // Otherwise, set the Custom Variables found in the cookie sent with this request
+ $goal += $visitCustomVariables;
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
if (isset($visitorInformation['custom_var_k' . $i])
&& strlen($visitorInformation['custom_var_k' . $i])
) {
@@ -239,8 +243,6 @@ class GoalManager
$goal['custom_var_v' . $i] = $visitorInformation['custom_var_v' . $i];
}
}
- // Otherwise, set the Custom Variables found in the cookie sent with this request
- $goal += $visitCustomVariables;
// Attributing the correct Referrer to this conversion.
// Priority order is as follows:
diff --git a/core/Tracker/Request.php b/core/Tracker/Request.php
index 3dbe3f98d8..df551e7d82 100644
--- a/core/Tracker/Request.php
+++ b/core/Tracker/Request.php
@@ -14,6 +14,7 @@ use Piwik\Config;
use Piwik\Cookie;
use Piwik\IP;
use Piwik\Piwik;
+use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Registry;
use Piwik\Tracker;
@@ -352,10 +353,11 @@ class Request
return array();
}
$customVariables = array();
+ $maxCustomVars = CustomVariables::getMaxCustomVariables();
foreach ($customVar as $id => $keyValue) {
$id = (int)$id;
if ($id < 1
- || $id > Tracker::MAX_CUSTOM_VARIABLES
+ || $id > $maxCustomVars
|| count($keyValue) != 2
|| (!is_string($keyValue[0]) && !is_numeric($keyValue[0]))
) {
@@ -379,7 +381,7 @@ class Request
public static function truncateCustomVariable($input)
{
- return substr(trim($input), 0, Tracker::MAX_LENGTH_CUSTOM_VARIABLE);
+ return substr(trim($input), 0, CustomVariables::getMaxLengthCustomVariables());
}
protected function shouldUseThirdPartyCookie()
diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php
index cfca27271a..fecab8125e 100644
--- a/core/Tracker/Visit.php
+++ b/core/Tracker/Visit.php
@@ -13,6 +13,7 @@ use Piwik\Common;
use Piwik\Config;
use Piwik\IP;
use Piwik\Piwik;
+use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Tracker;
use DeviceDetector;
@@ -396,12 +397,11 @@ class Visit implements VisitInterface
$selectCustomVariables = '';
// No custom var were found in the request, so let's copy the previous one in a potential conversion later
if (!$this->visitorCustomVariables) {
- $selectCustomVariables = ',
- 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';
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+
+ for ($index = 1; $index <= $maxCustomVariables; $index++) {
+ $selectCustomVariables .= ', custom_var_k' . $index . ', custom_var_v' . $index;
+ }
}
$persistedVisitAttributes = $this->getVisitFieldsPersist();
@@ -513,7 +513,8 @@ class Visit implements VisitInterface
// Custom Variables copied from Visit in potential later conversion
if (!empty($selectCustomVariables)) {
- for ($i = 1; $i <= Tracker::MAX_CUSTOM_VARIABLES; $i++) {
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
if (isset($visitRow['custom_var_k' . $i])
&& strlen($visitRow['custom_var_k' . $i])
) {
diff --git a/core/Updater.php b/core/Updater.php
index 59587cb19b..a1f39fb71b 100644
--- a/core/Updater.php
+++ b/core/Updater.php
@@ -287,16 +287,41 @@ class Updater
static function updateDatabase($file, $sqlarray)
{
foreach ($sqlarray as $update => $ignoreError) {
- try {
- Db::exec($update);
- } catch (\Exception $e) {
- if (($ignoreError === false)
- || !Db::get()->isErrNo($e, $ignoreError)
- ) {
- $message = $file . ":\nError trying to execute the query '" . $update . "'.\nThe error was: " . $e->getMessage();
- throw new UpdaterErrorException($message);
- }
- }
+ self::executeMigrationQuery($update, $ignoreError, $file);
+ }
+ }
+
+ /**
+ * Executes a database update query.
+ *
+ * @param string $updateSql Update SQL query.
+ * @param int|false $errorToIgnore A MySQL error code to ignore.
+ * @param string $file The Update file that's calling this method.
+ */
+ public static function executeMigrationQuery($updateSql, $errorToIgnore, $file)
+ {
+ try {
+ Db::exec($updateSql);
+ } catch (\Exception $e) {
+ self::handleQueryError($e, $updateSql, $errorToIgnore, $file);
+ }
+ }
+
+ /**
+ * Handle an error that is thrown from a database query.
+ *
+ * @param \Exception $e the exception thrown.
+ * @param string $updateSql Update SQL query.
+ * @param int|false $errorToIgnore A MySQL error code to ignore.
+ * @param string $file The Update file that's calling this method.
+ */
+ public static function handleQueryError($e, $updateSql, $errorToIgnore, $file)
+ {
+ if (($errorToIgnore === false)
+ || !Db::get()->isErrNo($e, $errorToIgnore)
+ ) {
+ $message = $file . ":\nError trying to execute the query '" . $updateSql . "'.\nThe error was: " . $e->getMessage();
+ throw new UpdaterErrorException($message);
}
}
}
diff --git a/core/Updates/2.1.1-b11.php b/core/Updates/2.1.1-b11.php
new file mode 100644
index 0000000000..b38f92e331
--- /dev/null
+++ b/core/Updates/2.1.1-b11.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Updates;
+
+use Piwik\Db;
+use Piwik\Updates;
+use Piwik\Updater;
+use Piwik\Date;
+use Piwik\Segment;
+use Piwik\ArchiveProcessor\Rules;
+use Piwik\Db\BatchInsert;
+use Piwik\DataAccess\ArchiveWriter;
+use Piwik\Plugins\VisitFrequency\API as VisitFrequencyApi;
+
+/**
+ */
+class Updates_2_1_1_b11 extends Updates
+{
+ static function update()
+ {
+ $returningMetrics = array(
+ 'nb_visits_returning',
+ 'nb_actions_returning',
+ 'max_actions_returning',
+ 'sum_visit_length_returning',
+ 'bounce_count_returning',
+ 'nb_visits_converted_returning',
+ 'nb_uniq_visitors_returning'
+ );
+
+ $now = Date::factory('now')->getDatetime();
+
+ $archiveNumericTables = Db::get()->fetchCol("SHOW TABLES LIKE '%archive_numeric%'");
+
+ // for each numeric archive table, copy *_returning metrics to VisitsSummary metrics w/ the appropriate
+ // returning visit segment
+ foreach ($archiveNumericTables as $table) {
+ // get archives w/ *._returning
+ $sql = "SELECT idarchive, idsite, period, date1, date2
+ FROM $table
+ WHERE name IN ('" . implode("','", $returningMetrics) . "')
+ GROUP BY idarchive";
+ $idArchivesWithReturning = Db::fetchAll($sql);
+
+ // get archives for visitssummary returning visitor segment
+ $sql = "SELECT idarchive, idsite, period, date1, date2
+ FROM $table
+ WHERE name = ?
+ GROUP BY idarchive";
+ $visitSummaryReturningSegmentDone = Rules::getDoneFlagArchiveContainsOnePlugin(
+ new Segment(VisitFrequencyApi::RETURNING_VISITOR_SEGMENT, $idSites = array()), 'VisitsSummary');
+ $idArchivesWithVisitReturningSegment = Db::fetchAll($sql, array($visitSummaryReturningSegmentDone));
+
+ // collect info for new visitssummary archives have to be created to match archives w/ *._returning
+ // metrics
+ $missingIdArchives = array();
+ $idArchiveMappings = array();
+ foreach ($idArchivesWithReturning as $row) {
+ $withMetricsIdArchive = $row['idarchive'];
+ foreach ($idArchivesWithVisitReturningSegment as $segmentRow) {
+ if ($row['idsite'] == $segmentRow['idsite']
+ && $row['period'] == $segmentRow['period']
+ && $row['date1'] == $segmentRow['date1']
+ && $row['date2'] == $segmentRow['date2']
+ ) {
+ $idArchiveMappings[$withMetricsIdArchive] = $segmentRow['idarchive'];
+ }
+ }
+
+ if (!isset($idArchiveMappings[$withMetricsIdArchive])) {
+ $missingIdArchives[$withMetricsIdArchive] = $row;
+ }
+ }
+
+ // if there are missing idarchives, fill out new archive row values
+ if (!empty($missingIdArchives)) {
+ $newIdArchiveStart = Db::fetchOne("SELECT MAX(idarchive) FROM $table") + 1;
+ foreach ($missingIdArchives as $withMetricsIdArchive => &$rowToInsert) {
+ $idArchiveMappings[$withMetricsIdArchive] = $newIdArchiveStart;
+
+ $rowToInsert['idarchive'] = $newIdArchiveStart;
+ $rowToInsert['ts_archived'] = $now;
+ $rowToInsert['name'] = $visitSummaryReturningSegmentDone;
+ $rowToInsert['value'] = ArchiveWriter::DONE_OK;
+
+ ++$newIdArchiveStart;
+ }
+
+ // add missing archives
+ try {
+ BatchInsert::tableInsertBatch($table, array_keys(reset($missingIdArchives)), $missingIdArchives, $throwException = false);
+ } catch (\Exception $ex) {
+ Updater::handleQueryError($ex, "<batch insert>", false, __FILE__);
+ }
+ }
+
+ // update idarchive & name columns in rows with *._returning metrics
+ $updateSqlPrefix = "UPDATE $table
+ SET idarchive = CASE idarchive ";
+ $updateSqlSuffix = " END, name = CASE name ";
+ foreach ($returningMetrics as $metric) {
+ $newMetricName = substr($metric, 0, strlen($metric) - strlen(VisitFrequencyApi::COLUMN_SUFFIX));
+ $updateSqlSuffix .= "WHEN '$metric' THEN '" . $newMetricName . "' ";
+ }
+ $updateSqlSuffix .= " END WHERE idarchive IN (" . implode(',', array_keys($idArchiveMappings)) . ")
+ AND name IN ('" . implode("','", $returningMetrics) . "')";
+
+ // update only 1000 rows at a time so we don't send too large an SQL query to MySQL
+ foreach (array_chunk($missingIdArchives, 1000, $preserveKeys = true) as $chunk) {
+ $idArchives = array();
+
+ $updateSql = $updateSqlPrefix;
+ foreach ($chunk as $withMetricsIdArchive => $row) {
+ $updateSql .= "WHEN $withMetricsIdArchive THEN {$row['idarchive']} ";
+ }
+ $updateSql .= $updateSqlSuffix;
+
+ Updater::executeMigrationQuery($updateSql, false, __FILE__);
+ }
+ }
+ }
+}
diff --git a/core/Version.php b/core/Version.php
index 889a5cd065..fbe16426b5 100644
--- a/core/Version.php
+++ b/core/Version.php
@@ -21,5 +21,5 @@ final class Version
* The current Piwik version.
* @var string
*/
- const VERSION = '2.1.1-b10';
+ const VERSION = '2.1.1-b11';
}
diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php
index a7dbac5a77..2b4766aa36 100644
--- a/core/testMinimumPhpVersion.php
+++ b/core/testMinimumPhpVersion.php
@@ -71,8 +71,7 @@ if (!function_exists('Piwik_ExitWithMessage')) {
function Piwik_ShouldPrintBackTraceWithMessage()
{
$bool = (defined('PIWIK_PRINT_ERROR_BACKTRACE') && PIWIK_PRINT_ERROR_BACKTRACE)
- || (defined('PIWIK_TRACKER_DEBUG') && PIWIK_TRACKER_DEBUG)
- || \Piwik\API\ResponseBuilder::DISPLAY_BACKTRACE_DEBUG;
+ || !empty($GLOBALS['PIWIK_TRACKER_DEBUG']);
return $bool;
}
diff --git a/lang/en.json b/lang/en.json
index 64cc6df84c..82dfe85117 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -928,7 +928,7 @@
"DoYouHaveBugReportOrFeatureRequest": "Do you have a bug to report or a feature request?",
"ViewUserGuides": "Learn how to configure Piwik and how to effectively analyze your data with our %1$suser guides%2$s",
"ViewAnswersToFAQ": "View answers to %sFrequently Asked Questions%s",
- "VisitTheForums": "Visit the %s Forums%s",
+ "VisitTheForums": "Visit the %s Forums%s and get help from the community of Piwik users",
"LearnWaysToParticipate": "Learn about all the ways you can %s participate%s",
"HowToCreateIssue": "Please read the recommendations on writing a good %1$sbug report%2$s or %3$sfeature request%4$s. Then %5$sregister%6$s or %7$slogin%8$s on our issue tracker and create a %9$snew issue%10$s.",
"SpecialRequest": "Do you have a special request for the Piwik team?",
diff --git a/piwik.php b/piwik.php
index c6eb9c822b..dcb5db5349 100644
--- a/piwik.php
+++ b/piwik.php
@@ -12,6 +12,9 @@ use Piwik\Common;
use Piwik\Timer;
use Piwik\Tracker;
+// Note: if you wish to debug the Tracking API please see this documentation:
+// http://developer.piwik.org/api-reference/tracking-api#debugging-the-tracker
+
$GLOBALS['PIWIK_TRACKER_DEBUG_FORCE_SCHEDULED_TASKS'] = false;
define('PIWIK_ENABLE_TRACKING', true);
diff --git a/plugins/API/Controller.php b/plugins/API/Controller.php
index b80eb577a3..349cdacbfb 100644
--- a/plugins/API/Controller.php
+++ b/plugins/API/Controller.php
@@ -62,7 +62,10 @@ class Controller extends \Piwik\Plugin\Controller
$segment['type'] = 'dimension';
}
- $onlyDisplay = array('customVariableName1', 'customVariableName2', 'customVariableValue1', 'customVariableValue2', 'customVariablePageName1', 'customVariablePageValue1');
+ $onlyDisplay = array('customVariableName1', 'customVariableName2',
+ 'customVariableValue1', 'customVariableValue2',
+ 'customVariablePageName1', 'customVariablePageValue1');
+
$customVariableWillBeDisplayed = in_array($segment['segment'], $onlyDisplay);
// Don't display more than 4 custom variables name/value rows
if ($segment['category'] == 'Custom Variables'
diff --git a/plugins/CoreAdminHome/Controller.php b/plugins/CoreAdminHome/Controller.php
index fbc351e756..de24bf76f1 100644
--- a/plugins/CoreAdminHome/Controller.php
+++ b/plugins/CoreAdminHome/Controller.php
@@ -19,6 +19,7 @@ use Piwik\Nonce;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Plugins\CorePluginsAdmin\UpdateCommunication;
+use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Plugins\LanguagesManager\API as APILanguagesManager;
use Piwik\Plugins\LanguagesManager\LanguagesManager;
use Piwik\Plugins\SitesManager\API as APISitesManager;
@@ -210,6 +211,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
$view->defaultReportSiteName = Site::getNameFor($view->idSite);
$view->defaultSiteRevenue = \Piwik\MetricsFormatter::getCurrencySymbol($view->idSite);
+ $view->maxCustomVariables = CustomVariables::getMaxCustomVariables();
$allUrls = APISitesManager::getInstance()->getSiteUrlsFromId($view->idSite);
if (isset($allUrls[1])) {
diff --git a/plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js b/plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js
index d5a9f7363f..03d854c176 100644
--- a/plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js
+++ b/plugins/CoreAdminHome/javascripts/jsTrackingGenerator.js
@@ -12,46 +12,9 @@
exports = require('piwik/Tracking');
/**
- * Singleton class used to trigger events on. Plugins can bind to these events
- * to customize the tracking code shown to users.
+ * This class is deprecated. Use server-side events instead.
*
- * The following events are triggered:
- *
- * - customizeJavaScriptParams: function (eventObject, params)
- *
- * Triggered before tracking JavaScript is generated. This event can be used to
- * customize how the generated code looks, without having to parse JavaScript.
- *
- * params is an object containing the data used to create the JavaScript tracking
- * code.
- *
- * - customizeJavaScript: function (eventObject, eventData)
- *
- * Triggered after tracking JavaScript is generated. This event can be used to
- * customize how the generated code looks, if it cannot be done with the
- * customizeJavaScriptParams event.
- *
- * eventData is an object with one element, 'code', which holds the JavaScript
- * tracking code.
- *
- * - customizeTrackerLinkParams: function (eventObject, params)
- *
- * Triggered before the tracking link is generated. This event can be used to
- * customize how the generated link looks, without having to parse the HTML
- * link code.
- *
- * params is an object containing the data used to create the tracking link.
- *
- * - customizeTrackerLink: function (eventObject, eventData)
- *
- * Triggered after the tracking link is generated. This event can be used to
- * customize how the generated link looks, if the customization cannot be done
- * with the customizeTrackerLinkParams event.
- *
- * eventData is an object with one element, 'code', which holds the tracking
- * link HTML.
- *
- * @constructor
+ * @deprecated
*/
var TrackingCodeGenerator = function () {
// empty
@@ -64,6 +27,7 @@
// get preloaded server-side data necessary for code generation
var dataElement = $('#js-tracking-generator-data'),
currencySymbols = JSON.parse(dataElement.attr('data-currencies')),
+ maxCustomVariables = parseInt(dataElement.attr('max-custom-variables'), 10),
siteUrls = {},
siteCurrencies = {},
allGoals = {},
@@ -185,150 +149,81 @@
};
// function that generates JS code
- var generateJsCode = function () {
- // get params used to generate JS code
- var params = {
- idSite: $('#js-tracker-website').attr('siteid'),
- groupPageTitlesByDomain: $('#javascript-tracking-group-by-domain').is(':checked'),
- mergeSubdomains: $('#javascript-tracking-all-subdomains').is(':checked'),
- mergeAliasUrls: $('#javascript-tracking-all-aliases').is(':checked'),
- visitorCustomVariables: getCustomVariables('javascript-tracking-visitor-cv'),
- pageCustomVariables: getCustomVariables('javascript-tracking-page-cv'),
- customCampaignNameQueryParam: null,
- customCampaignKeywordParam: null,
- doNotTrack: $('#javascript-tracking-do-not-track').is(':checked'),
- piwikHost: piwikHost,
- piwikPath: piwikPath
- };
-
- if ($('#custom-campaign-query-params-check').is(':checked')) {
- params.customCampaignNameQueryParam = $('#custom-campaign-name-query-param').val();
- params.customCampaignKeywordParam = $('#custom-campaign-keyword-query-param').val();
- }
-
- // allow plugins to modify data used to generate tracking code
- $(TrackingCodeGeneratorSingleton).trigger('customizeJavaScriptParams', params);
-
- var idSite = params.idSite;
-
- // generate JS
- // changes made to this code should be mirrored in core/Piwik.php function getJavascriptCode()
- var result = '<!-- Piwik -->\n\
-<script type="text/javascript">\n\
- var _paq = _paq || [];\n';
-
- if (params.groupPageTitlesByDomain) {
- result += ' _paq.push(["setDocumentTitle", document.domain + "/" + document.title]);\n';
- }
-
- if (params.mergeSubdomains) {
- var mainHostAllSub = '*.' + getHostNameFromUrl(siteUrls[idSite][0]);
- result += ' _paq.push(["setCookieDomain", ' + JSON.stringify(mainHostAllSub) + ']);\n';
- }
-
- if (params.mergeAliasUrls) {
- var siteHosts = [];
- for (var i = 0; i != siteUrls[idSite].length; ++i) {
- siteHosts[i] = '*.' + getHostNameFromUrl(siteUrls[idSite][i]);
+ var generateJsCodeAjax = null,
+ generateJsCode = function () {
+ // get params used to generate JS code
+ var params = {
+ piwikUrl: piwikHost + piwikPath,
+ groupPageTitlesByDomain: $('#javascript-tracking-group-by-domain').is(':checked') ? 1 : 0,
+ mergeSubdomains: $('#javascript-tracking-all-subdomains').is(':checked') ? 1 : 0,
+ mergeAliasUrls: $('#javascript-tracking-all-aliases').is(':checked') ? 1 : 0,
+ visitorCustomVariables: getCustomVariables('javascript-tracking-visitor-cv'),
+ pageCustomVariables: getCustomVariables('javascript-tracking-page-cv'),
+ customCampaignNameQueryParam: null,
+ customCampaignKeywordParam: null,
+ doNotTrack: $('#javascript-tracking-do-not-track').is(':checked') ? 1 : 0,
+ };
+
+ if ($('#custom-campaign-query-params-check').is(':checked')) {
+ params.customCampaignNameQueryParam = $('#custom-campaign-name-query-param').val();
+ params.customCampaignKeywordParam = $('#custom-campaign-keyword-query-param').val();
}
- result += ' _paq.push(["setDomains", ' + JSON.stringify(siteHosts) + ']);\n';
- }
-
- if (params.visitorCustomVariables.length) {
- result += ' // you can set up to 5 custom variables for each visitor\n';
- result += getCustomVariableJS(params.visitorCustomVariables, 'visit');
- }
-
- if (params.pageCustomVariables.length) {
- result += ' // you can set up to 5 custom variables for each action (page view, ' +
- 'download, click, site search)\n';
- result += getCustomVariableJS(params.pageCustomVariables, 'page');
- }
- if (params.customCampaignNameQueryParam) {
- result += ' _paq.push(["setCampaignNameKey", ' + JSON.stringify(params.customCampaignNameQueryParam) + ']);\n';
- }
-
- if (params.customCampaignKeywordParam) {
- result += ' _paq.push(["setCampaignKeywordKey", ' + JSON.stringify(params.customCampaignKeywordParam) + ']);\n';
- }
-
- if (params.doNotTrack) {
- result += ' _paq.push(["setDoNotTrack", true]);\n';
- }
-
- result += ' _paq.push(["trackPageView"]);\n\
- _paq.push(["enableLinkTracking"]);\n\n\
- (function() {\n\
- var u=(("https:" == document.location.protocol) ? "https" : "http") + "://' + params.piwikHost + params.piwikPath + '/";\n\
- _paq.push(["setTrackerUrl", u+"piwik.php"]);\n\
- _paq.push(["setSiteId", ' + JSON.stringify(idSite) + ']);\n\
- var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";\n\
- g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);\n\
- })();\n\
-</script>\n\
-'+'<!-- End Piwik Code -->';
-
- // allow plugins to modify generated JavaScript
- var eventData = {code: result, piwikHost: piwikHost };
- $(TrackingCodeGeneratorSingleton).trigger('customizeJavaScript', eventData);
- result = eventData.code;
-
- $('#javascript-text').find('textarea').val(result)
- };
-
- // function that generates image tracker link
- var generateImageTrackerLink = function () {
- // get data used to generate the link
- var generateDataParams = {
- idSite: $('#image-tracker-website').attr('siteid'),
- actionName: $('#image-tracker-action-name').val(),
- piwikHost: piwikHost,
- piwikPath: piwikPath
- };
-
- if ($('#image-tracking-goal-check').is(':checked')) {
- generateDataParams.idGoal = $('#image-tracker-goal').val();
- if (generateDataParams.idGoal) {
- generateDataParams.revenue = $('#image-tracker-advanced-options').find('.revenue').val();
+ if (generateJsCodeAjax) {
+ generateJsCodeAjax.abort();
}
- }
-
- // allow plugins to modify data used to generate tracking code
- $(TrackingCodeGeneratorSingleton).trigger('customizeTrackerLinkParams', generateDataParams);
- // generate link HTML
- var params = {
- idsite: generateDataParams.idSite,
- rec: 1
+ generateJsCodeAjax = new ajaxHelper();
+ generateJsCodeAjax.addParams({
+ module: 'API',
+ format: 'json',
+ method: 'SitesManager.getJavascriptTag',
+ idSite: $('#js-tracker-website').attr('siteid')
+ }, 'GET');
+ generateJsCodeAjax.addParams(params, 'POST');
+ generateJsCodeAjax.setCallback(function (response) {
+ generateJsCodeAjax = null;
+
+ $('#javascript-text').find('textarea').val(response.value);
+ });
+ generateJsCodeAjax.send();
};
- if (generateDataParams.actionName) {
- params.action_name = generateDataParams.actionName;
- }
-
- if (generateDataParams.idGoal) {
- params.idGoal = generateDataParams.idGoal;
- if (generateDataParams.revenue) {
- params.revenue = generateDataParams.revenue;
+ // function that generates image tracker link
+ var generateImageTrackingAjax = null,
+ generateImageTrackerLink = function () {
+ // get data used to generate the link
+ var generateDataParams = {
+ piwikUrl: piwikHost + piwikPath,
+ actionName: $('#image-tracker-action-name').val(),
+ };
+
+ if ($('#image-tracking-goal-check').is(':checked')) {
+ generateDataParams.idGoal = $('#image-tracker-goal').val();
+ if (generateDataParams.idGoal) {
+ generateDataParams.revenue = $('#image-tracker-advanced-options').find('.revenue').val();
+ }
}
- }
-
- var piwikURL = ("https:" == document.location.protocol ? "https://" : "http://") + generateDataParams.piwikHost
- + generateDataParams.piwikPath + '/piwik.php';
- var result = '<!-- Piwik Image Tracker -->\n\
-<img src="' + piwikURL + '?' + $.param(params) + '" style="border:0" alt="" />\n\
-<!-- End Piwik -->';
-
- // allow plugins to modify tracking link code
- var eventData = {code: result};
- $(TrackingCodeGeneratorSingleton).trigger('customizeTrackerLink', eventData);
- result = eventData.code;
+ if (generateImageTrackingAjax) {
+ generateImageTrackingAjax.abort();
+ }
- result = result.replace(/[&]/g, "&amp;");
- $('#image-tracking-text').find('textarea').val(result);
- };
+ generateImageTrackingAjax = new ajaxHelper();
+ generateImageTrackingAjax.addParams({
+ module: 'API',
+ format: 'json',
+ method: 'SitesManager.getImageTrackingCode',
+ idSite: $('#image-tracker-website').attr('siteid')
+ }, 'GET');
+ generateImageTrackingAjax.addParams(generateDataParams, 'POST');
+ generateImageTrackingAjax.setCallback(function (response) {
+ generateImageTrackingAjax = null;
+
+ $('#image-tracking-text').find('textarea').val(response.value);
+ });
+ generateImageTrackingAjax.send();
+ };
// on image link tracker site change, change available goals
$('#image-tracker-website').bind('change', function (e, site) {
@@ -374,8 +269,8 @@
row.before(newRow);
// hide add button if max # of custom variables has been reached
- // (5 custom variables + 1 row for add new row)
- if ($('tr', row.parent()).length == 6) {
+ // (X custom variables + 1 row for add new row)
+ if ($('tr', row.parent()).length == (maxCustomVariables + 1)) {
$(this).hide();
}
@@ -403,7 +298,7 @@
$('#js-tracker-website').attr('siteid'),
'#js-code-options,#image-tracking-code-options',
function () {
- var imageTrackerSiteId = $('#image-tracker-website').find('.custom_select_main_link').attr('data-siteid');
+ var imageTrackerSiteId = $('#image-tracker-website').attr('siteid');
resetGoalSelectItems(imageTrackerSiteId, 'image-tracker-goal');
generateJsCode();
diff --git a/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig b/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig
index 10ac52386a..2666ec62ac 100644
--- a/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig
+++ b/plugins/CoreAdminHome/templates/trackingCodeGenerator.twig
@@ -7,7 +7,7 @@
{% endblock %}
{% block content %}
-<div id="js-tracking-generator-data" data-currencies="{{ currencySymbols|json_encode }}"></div>
+<div id="js-tracking-generator-data" max-custom-variables="{{ maxCustomVariables|e('html_attr') }}" data-currencies="{{ currencySymbols|json_encode }}"></div>
<h2 piwik-enriched-headline
feature-name="{{ 'CoreAdminHome_TrackingCode'|translate }}"
diff --git a/plugins/CoreConsole/Commands/CoreArchiver.php b/plugins/CoreConsole/Commands/CoreArchiver.php
index 606f1d4941..0fe60d3bc9 100644
--- a/plugins/CoreConsole/Commands/CoreArchiver.php
+++ b/plugins/CoreConsole/Commands/CoreArchiver.php
@@ -18,24 +18,7 @@ class CoreArchiver extends ConsoleCommand
{
protected function configure()
{
- $this->setName('core:archive');
- $this->setDescription("Runs the CLI archiver. It usually runs as a cron and is a useful tool for general maintenance, and pre-process reports for a Fast dashboard rendering.");
- $this->setHelp("* It is recommended to run the script with the option --piwik-domain=[piwik-server-url] only. Other options are not required.
-* This script should be executed every hour via crontab, or as a daemon.
-* You can also run it via http:// by specifying the Super User &token_auth=XYZ as a parameter ('Web Cron'),
- but it is recommended to run it via command line/CLI instead.
-* If you have any suggestion about this script, please let the team know at hello@piwik.org
-* Enjoy!");
- $this->addOption('url', null, InputOption::VALUE_REQUIRED, "Mandatory option as an alternative to '--piwik-domain'. Must be set to the Piwik base URL.\nFor example: --url=http://analytics.example.org/ or --url=https://example.org/piwik/");
- $this->addOption('force-all-websites', null, InputOption::VALUE_NONE, "If specified, the script will trigger archiving on all websites and all past dates.\nYou may use --force-all-periods=[seconds] to trigger archiving on those websites\nthat had visits in the last [seconds] seconds.");
- $this->addOption('force-all-periods', null, InputOption::VALUE_OPTIONAL, "Limits archiving to websites with some traffic in the last [seconds] seconds. \nFor example --force-all-periods=86400 will archive websites that had visits in the last 24 hours. \nIf [seconds] is not specified, all websites with visits in the last " . CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE . "\n seconds (" . round( CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE/86400 ) ." days) will be archived.");
- $this->addOption('force-timeout-for-periods', null, InputOption::VALUE_OPTIONAL, "The current week/ current month/ current year will be processed at most every [seconds].\nIf not specified, defaults to ". CronArchive::SECONDS_DELAY_BETWEEN_PERIOD_ARCHIVES.".");
- $this->addOption('force-date-last-n', null, InputOption::VALUE_REQUIRED, "This script calls the API with period=lastN. You can force the N in lastN by specifying this value.");
- $this->addOption('force-idsites', null,InputOption::VALUE_REQUIRED, "Restricts archiving to the specified website IDs, comma separated list.");
- $this->addOption('skip-idsites', null, InputOption::VALUE_REQUIRED, "If the specified websites IDs were to be archived, skip them instead.");
- $this->addOption('disable-scheduled-tasks', null, InputOption::VALUE_NONE, "Skips executing Scheduled tasks (sending scheduled reports, db optimization, etc.).");
- $this->addOption('xhprof', null, InputOption::VALUE_NONE, "Enables XHProf profiler for this archive.php run. Requires XHPRof (see tests/README.xhprof.md).");
- $this->addOption('accept-invalid-ssl-certificate', null, InputOption::VALUE_NONE, "It is _NOT_ recommended to use this argument. Instead, you should use a valid SSL certificate!\nIt can be useful if you specified --url=https://... or if you are using Piwik with force_ssl=1");
+ $this->configureArchiveCommand($this);
}
protected function execute(InputInterface $input, OutputInterface $output)
@@ -46,4 +29,27 @@ class CoreArchiver extends ConsoleCommand
include PIWIK_INCLUDE_PATH . '/misc/cron/archive.php';
}
+
+ // This is reused by another console command
+ static public function configureArchiveCommand(ConsoleCommand $command)
+ {
+ $command->setName('core:archive');
+ $command->setDescription("Runs the CLI archiver. It is an important tool for general maintenance and to keep Piwik very fast.");
+ $command->setHelp("* It is recommended to run the script with the option --piwik-domain=[piwik-server-url] only. Other options are not required.
+* This script should be executed every hour via crontab, or as a daemon.
+* You can also run it via http:// by specifying the Super User &token_auth=XYZ as a parameter ('Web Cron'),
+ but it is recommended to run it via command line/CLI instead.
+* If you have any suggestion about this script, please let the team know at hello@piwik.org
+* Enjoy!");
+ $command->addOption('url', null, InputOption::VALUE_REQUIRED, "Mandatory option as an alternative to '--piwik-domain'. Must be set to the Piwik base URL.\nFor example: --url=http://analytics.example.org/ or --url=https://example.org/piwik/");
+ $command->addOption('force-all-websites', null, InputOption::VALUE_NONE, "If specified, the script will trigger archiving on all websites and all past dates.\nYou may use --force-all-periods=[seconds] to trigger archiving on those websites\nthat had visits in the last [seconds] seconds.");
+ $command->addOption('force-all-periods', null, InputOption::VALUE_OPTIONAL, "Limits archiving to websites with some traffic in the last [seconds] seconds. \nFor example --force-all-periods=86400 will archive websites that had visits in the last 24 hours. \nIf [seconds] is not specified, all websites with visits in the last " . CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE . "\n seconds (" . round(CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE / 86400) . " days) will be archived.");
+ $command->addOption('force-timeout-for-periods', null, InputOption::VALUE_OPTIONAL, "The current week/ current month/ current year will be processed at most every [seconds].\nIf not specified, defaults to " . CronArchive::SECONDS_DELAY_BETWEEN_PERIOD_ARCHIVES . ".");
+ $command->addOption('force-date-last-n', null, InputOption::VALUE_REQUIRED, "This script calls the API with period=lastN. You can force the N in lastN by specifying this value.");
+ $command->addOption('force-idsites', null, InputOption::VALUE_OPTIONAL, 'If specified, archiving will be processed only for these Sites Ids (comma separated)');
+ $command->addOption('skip-idsites', null, InputOption::VALUE_OPTIONAL, 'If specified, archiving will be skipped for these websites (in case these website ids would have been archived).');
+ $command->addOption('disable-scheduled-tasks', null, InputOption::VALUE_NONE, "Skips executing Scheduled tasks (sending scheduled reports, db optimization, etc.).");
+ $command->addOption('xhprof', null, InputOption::VALUE_NONE, "Enables XHProf profiler for this archive.php run. Requires XHPRof (see tests/README.xhprof.md).");
+ $command->addOption('accept-invalid-ssl-certificate', null, InputOption::VALUE_NONE, "It is _NOT_ recommended to use this argument. Instead, you should use a valid SSL certificate!\nIt can be useful if you specified --url=https://... or if you are using Piwik with force_ssl=1");
+ }
} \ No newline at end of file
diff --git a/plugins/CoreConsole/Commands/SyncUITestScreenshots.php b/plugins/CoreConsole/Commands/SyncUITestScreenshots.php
index 639b7d3db5..3deb5d72e1 100644
--- a/plugins/CoreConsole/Commands/SyncUITestScreenshots.php
+++ b/plugins/CoreConsole/Commands/SyncUITestScreenshots.php
@@ -22,8 +22,8 @@ class SyncUITestScreenshots extends ConsoleCommand
protected function configure()
{
$this->setName('development:sync-ui-test-screenshots');
- $this->setDescription('This command is intended for Piwik core developers. It copies all processed screenshot '
- . 'tests on Travis to the expected screenshot directory.');
+ $this->setDescription('For Piwik core devs. Copies screenshots '
+ . 'from travis artifacts to tests/PHPUnit/UI/expected-ui-screenshots/');
$this->addArgument('buildnumber', InputArgument::REQUIRED, 'Travis build number you want to sync.');
$this->addArgument('screenshotsRegex', InputArgument::OPTIONAL,
'A regex to use when selecting screenshots to copy. If not supplied all screenshots are copied.', '.*');
diff --git a/plugins/CoreUpdater/Commands/Update.php b/plugins/CoreUpdater/Commands/Update.php
index 226117df1e..0417140767 100644
--- a/plugins/CoreUpdater/Commands/Update.php
+++ b/plugins/CoreUpdater/Commands/Update.php
@@ -27,7 +27,8 @@ class Update extends ConsoleCommand
protected function configure()
{
$this->setName('core:update');
- $this->setDescription('Triggers the upgrades for Piwik core and plugins. Useful after Piwik core files or some plugins were updated to latest files.');
+
+ $this->setDescription('Triggers upgrades. Use it after Piwik core or any plugin files have been updated.');
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Only prints out the SQL requests that would be executed during the upgrade');
}
diff --git a/plugins/CustomAlerts b/plugins/CustomAlerts
-Subproject c9edd879003ca7a9f75d81fe07ec6ff0c2340f9
+Subproject a1125e96827e12c7bd5c3d6107b9c162aace32f
diff --git a/plugins/CustomVariables/Archiver.php b/plugins/CustomVariables/Archiver.php
index bc9d9b3241..d7ae1ac015 100644
--- a/plugins/CustomVariables/Archiver.php
+++ b/plugins/CustomVariables/Archiver.php
@@ -59,7 +59,8 @@ class Archiver extends \Piwik\Plugin\Archiver
{
$this->dataArray = new DataArray();
- for ($i = 1; $i <= Tracker::MAX_CUSTOM_VARIABLES; $i++) {
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
$this->aggregateCustomVariable($i);
}
diff --git a/plugins/CustomVariables/Commands/Info.php b/plugins/CustomVariables/Commands/Info.php
new file mode 100644
index 0000000000..796c010f12
--- /dev/null
+++ b/plugins/CustomVariables/Commands/Info.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\CustomVariables\Commands;
+
+use Piwik\Common;
+use Piwik\Plugin\ConsoleCommand;
+use Piwik\Plugins\CustomVariables\CustomVariables;
+use Piwik\Plugins\CustomVariables\Model;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ */
+class Info extends ConsoleCommand
+{
+ protected function configure()
+ {
+ $this->setName('customvariables:info');
+ $this->setDescription('Get info about configured custom variables');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $maxVars = CustomVariables::getMaxCustomVariables();
+
+ if ($this->hasEverywhereSameAmountOfVariables()) {
+ $this->writeSuccessMessage($output, array(
+ 'Your Piwik is configured for ' . $maxVars . ' custom variables.'
+ ));
+ return;
+ }
+
+ $output->writeln('<error>There is a problem with your custom variables configuration:</error>');
+ $output->writeln('<error>Some database tables miss custom variables columns.</error>');
+ $output->writeln('');
+ $output->writeln('Your Piwik seems to be configured for ' . $maxVars . ' custom variables.');
+ $output->writeln('Executing "<comment>./console set-max-custom-variables ' . $maxVars . '</comment>" might fix this issue.');
+ $output->writeln('If not check the following tables whether they have the same columns starting with <comment>custom_var_</comment>: ');
+ foreach (Model::getScopes() as $scope) {
+ $output->writeln(Common::prefixTable($scope));
+ }
+ }
+
+ private function hasEverywhereSameAmountOfVariables()
+ {
+ $indexesBefore = null;
+
+ foreach (Model::getScopes() as $scope) {
+ $model = new Model($scope);
+ $indexes = $model->getCustomVarIndexes();
+
+ if (is_null($indexesBefore)) {
+ $indexesBefore = $indexes;
+ } elseif ($indexes != $indexesBefore) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/plugins/CustomVariables/Commands/SetNumberOfCustomVariables.php b/plugins/CustomVariables/Commands/SetNumberOfCustomVariables.php
new file mode 100644
index 0000000000..7bd7a8d43f
--- /dev/null
+++ b/plugins/CustomVariables/Commands/SetNumberOfCustomVariables.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\CustomVariables\Commands;
+
+use Piwik\Plugin\ConsoleCommand;
+use Piwik\Tracker\Cache;
+use Piwik\Plugins\CustomVariables\Model;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ */
+class SetNumberOfCustomVariables extends ConsoleCommand
+{
+ /**
+ * @var \Symfony\Component\Console\Helper\ProgressHelper
+ */
+ private $progress;
+
+ protected function configure()
+ {
+ $this->setName('customvariables:set-max-custom-variables');
+ $this->setDescription('Change the number of available custom variables');
+ $this->setHelp("Example:
+./console customvariables:set-max-custom-variables 10
+=> 10 custom variables will be available in total
+");
+ $this->addArgument('maxCustomVars', InputArgument::REQUIRED, 'Set the number of max available custom variables');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $numVarsToSet = $this->getNumVariablesToSet($input);
+ $numChangesToPerform = $this->getNumberOfChangesToPerform($numVarsToSet);
+
+ if (0 === $numChangesToPerform) {
+ $this->writeSuccessMessage($output, array(
+ 'Your Piwik is already configured for ' . $numVarsToSet . ' custom variables.'
+ ));
+ return;
+ }
+
+
+ $output->writeln('');
+ $output->writeln(sprintf('Configuring Piwik for %d custom variables', $numVarsToSet));
+
+
+ foreach (Model::getScopes() as $scope) {
+ $this->printChanges($scope, $numVarsToSet, $output);
+ }
+
+ if (!$this->confirmChange($output)) {
+ return;
+ }
+
+
+ $output->writeln('');
+ $output->writeln('Starting to apply changes');
+ $output->writeln('');
+
+
+ $this->progress = $this->initProgress($numChangesToPerform, $output);
+
+ foreach (Model::getScopes() as $scope) {
+ $this->performChange($scope, $numVarsToSet, $output);
+ }
+
+
+ Cache::clearCacheGeneral();
+ $this->progress->finish();
+
+ $this->writeSuccessMessage($output, array(
+ 'Your Piwik is now configured for ' . $numVarsToSet . ' custom variables.'
+ ));
+ }
+
+ private function initProgress($numChangesToPerform, OutputInterface $output)
+ {
+ /** @var \Symfony\Component\Console\Helper\ProgressHelper $progress */
+ $progress = $this->getHelperSet()->get('progress');
+ $progress->start($output, $numChangesToPerform);
+
+ return $progress;
+ }
+
+ private function performChange($scope, $numVarsToSet, OutputInterface $output)
+ {
+ $model = new Model($scope);
+ $numCurrentVars = $model->getCurrentNumCustomVars();
+ $numDifference = $this->getAbsoluteDifference($numCurrentVars, $numVarsToSet);
+
+ if ($numVarsToSet > $numCurrentVars) {
+ $this->addCustomVariables($model, $numDifference, $output);
+ return;
+ }
+
+ $this->removeCustomVariables($model, $numDifference, $output);
+ }
+
+ private function getNumVariablesToSet(InputInterface $input)
+ {
+ $maxCustomVars = $input->getArgument('maxCustomVars');
+
+ if (!is_numeric($maxCustomVars)) {
+ throw new \Exception('The number of available custom variables has to be a number');
+ }
+
+ $maxCustomVars = (int) $maxCustomVars;
+
+ if ($maxCustomVars <= 0) {
+ throw new \Exception('There has to be at least one custom variable');
+ }
+
+ return $maxCustomVars;
+ }
+
+ private function confirmChange(OutputInterface $output)
+ {
+ $output->writeln('');
+
+ $dialog = $this->getHelperSet()->get('dialog');
+ return $dialog->askConfirmation(
+ $output,
+ '<question>Are you sure you want to perform these actions? (y/N)</question>',
+ false
+ );
+ }
+
+ private function printChanges($scope, $numVarsToSet, OutputInterface $output)
+ {
+ $model = new Model($scope);
+ $scopeName = $model->getScopeName();
+ $highestIndex = $model->getHighestCustomVarIndex();
+ $numCurrentCustomVars = $model->getCurrentNumCustomVars();
+ $numVarsDifference = $this->getAbsoluteDifference($numCurrentCustomVars, $numVarsToSet);
+
+ $output->writeln('');
+ $output->writeln(sprintf('Scope "%s"', $scopeName));
+
+ if ($numVarsToSet > $numCurrentCustomVars) {
+
+ $indexes = $highestIndex + 1;
+ if (1 !== $numVarsDifference) {
+ $indexes .= ' - ' . ($highestIndex + $numVarsDifference);
+ }
+
+ $output->writeln(
+ sprintf('%s new custom variables having the index(es) %s will be ADDED', $numVarsDifference, $indexes)
+ );
+
+ } elseif ($numVarsToSet < $numCurrentCustomVars) {
+
+ $indexes = $highestIndex - $numVarsDifference + 1;
+
+ if (1 !== $numVarsDifference) {
+ $indexes .= ' - ' . $highestIndex;
+ }
+
+ $output->writeln(
+ sprintf("%s existing custom variables having the index(es) %s will be REMOVED.", $numVarsDifference, $indexes)
+ );
+ $output->writeln('<comment>This is an irreversible change</comment>');
+ }
+ }
+
+ private function getAbsoluteDifference($currentNumber, $numberToSet)
+ {
+ return abs($numberToSet - $currentNumber);
+ }
+
+ private function removeCustomVariables(Model $model, $numberOfVarsToRemove, OutputInterface $output)
+ {
+ for ($index = 0; $index < $numberOfVarsToRemove; $index++) {
+ $indexRemoved = $model->removeCustomVariable();
+ $this->progress->advance();
+ $output->writeln(' <info>Removed a variable in scope "' . $model->getScopeName() . '" having the index ' . $indexRemoved . '</info>');
+ }
+ }
+
+ private function addCustomVariables(Model $model, $numberOfVarsToAdd, OutputInterface $output)
+ {
+ for ($index = 0; $index < $numberOfVarsToAdd; $index++) {
+ $indexAdded = $model->addCustomVariable();
+ $this->progress->advance();
+ $output->writeln(' <info>Added a variable in scope "' . $model->getScopeName() . '" having the index ' . $indexAdded . '</info>');
+ }
+ }
+
+ private function getNumberOfChangesToPerform($numVarsToSet)
+ {
+ $numChangesToPerform = 0;
+
+ foreach (Model::getScopes() as $scope) {
+ $model = new Model($scope);
+ $numCurrentCustomVars = $model->getCurrentNumCustomVars();
+ $numChangesToPerform += $this->getAbsoluteDifference($numCurrentCustomVars, $numVarsToSet);
+ }
+
+ return $numChangesToPerform;
+ }
+}
diff --git a/plugins/CustomVariables/CustomVariables.php b/plugins/CustomVariables/CustomVariables.php
index 12bc5b007b..b4e71517a3 100644
--- a/plugins/CustomVariables/CustomVariables.php
+++ b/plugins/CustomVariables/CustomVariables.php
@@ -14,6 +14,7 @@ use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Tracker;
use Piwik\WidgetsList;
+use Piwik\Tracker\Cache;
/**
*/
@@ -38,6 +39,7 @@ class CustomVariables extends \Piwik\Plugin
'API.getReportMetadata' => 'getReportMetadata',
'API.getSegmentDimensionMetadata' => 'getSegmentsMetadata',
'ViewDataTable.configure' => 'configureViewDataTable',
+ 'Console.addCommands' => 'addConsoleCommands'
);
return $hooks;
}
@@ -52,6 +54,51 @@ class CustomVariables extends \Piwik\Plugin
MenuMain::getInstance()->add('General_Visitors', 'CustomVariables_CustomVariables', array('module' => 'CustomVariables', 'action' => 'index'), $display = true, $order = 50);
}
+ public function install()
+ {
+ Model::install();
+ }
+
+ /**
+ * There are also some hardcoded places in JavaScript
+ * @return int
+ */
+ public static function getMaxLengthCustomVariables()
+ {
+ return 200;
+ }
+
+ public static function getMaxCustomVariables()
+ {
+ $cache = Cache::getCacheGeneral();
+ $cacheKey = 'CustomVariables.MaxNumCustomVariables';
+
+ if (!array_key_exists($cacheKey, $cache)) {
+
+ $maxCustomVar = 0;
+
+ foreach (Model::getScopes() as $scope) {
+ $model = new Model($scope);
+ $highestIndex = $model->getHighestCustomVarIndex();
+
+ if ($highestIndex > $maxCustomVar) {
+ $maxCustomVar = $highestIndex;
+ }
+ }
+
+ $cache[$cacheKey] = $maxCustomVar;
+ Cache::setCacheGeneral($cache);
+ }
+
+ return $cache[$cacheKey];
+ }
+
+ public function addConsoleCommands(&$commands)
+ {
+ $commands[] = __NAMESPACE__ . '\\Commands\\SetNumberOfCustomVariables';
+ $commands[] = __NAMESPACE__ . '\\Commands\\Info';
+ }
+
/**
* Returns metadata for available reports
*/
@@ -81,7 +128,9 @@ class CustomVariables extends \Piwik\Plugin
public function getSegmentsMetadata(&$segments)
{
- for ($i = 1; $i <= Tracker::MAX_CUSTOM_VARIABLES; $i++) {
+ $maxCustomVariables = self::getMaxCustomVariables();
+
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
$segments[] = array(
'type' => 'dimension',
'category' => 'CustomVariables_CustomVariables',
diff --git a/plugins/CustomVariables/Model.php b/plugins/CustomVariables/Model.php
new file mode 100644
index 0000000000..c2c425b06e
--- /dev/null
+++ b/plugins/CustomVariables/Model.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CustomVariables;
+
+use Piwik\Common;
+use Piwik\DataTable;
+use Piwik\Db;
+use Piwik\Log;
+
+class Model
+{
+ const SCOPE_PAGE = 'log_link_visit_action';
+ const SCOPE_VISIT = 'log_visit';
+ const SCOPE_CONVERSION = 'log_conversion';
+
+ private $scope = null;
+
+ public function __construct($scope)
+ {
+ if (empty($scope) || !in_array($scope, $this->getScopes())) {
+ throw new \Exception('Invalid custom variable scope');
+ }
+
+ $this->scope = $scope;
+ }
+
+ public function getScopeName()
+ {
+ // actually we should have a class for each scope but don't want to overengineer it for now
+ switch ($this->scope) {
+ case self::SCOPE_PAGE:
+ return 'Page';
+ case self::SCOPE_VISIT:
+ return 'Visit';
+ case self::SCOPE_CONVERSION:
+ return 'Conversion';
+ }
+ }
+
+ /**
+ * @see getHighestCustomVarIndex()
+ * @return int
+ */
+ public function getCurrentNumCustomVars()
+ {
+ $indexes = $this->getCustomVarIndexes();
+
+ return count($indexes);
+ }
+
+ /**
+ * result of getHighestCustomVarIndex() can be different to getCurrentNumCustomVars() in case there are some missing
+ * custom variable indexes. For instance in case of manual changes on the DB
+ *
+ * custom_var_v1
+ * custom_var_v2
+ * custom_var_v4
+ *
+ * getHighestCustomVarIndex() -> returns 4
+ * getCurrentNumCustomVars() -> returns 3
+ *
+ * @return int
+ */
+ public function getHighestCustomVarIndex()
+ {
+ $indexes = $this->getCustomVarIndexes();
+
+ if (empty($indexes)) {
+ return 0;
+ }
+
+ return max($indexes);
+ }
+
+ public function getCustomVarIndexes()
+ {
+ $columns = $this->getCustomVarColumnNames();
+
+ if (empty($columns)) {
+ return array();
+ }
+
+ $indexes = array_map(function ($column) {
+ return Model::getCustomVariableIndexFromFieldName($column);
+ }, $columns);
+
+ return array_values(array_unique($indexes));
+ }
+
+ private function getCustomVarColumnNames()
+ {
+ $dbTable = $this->getDbTableName();
+ $columns = Db::getColumnNamesFromTable($dbTable);
+
+ $customVarColumns = array_filter($columns, function ($column) {
+ return false !== strpos($column, 'custom_var_');
+ });
+
+ return $customVarColumns;
+ }
+
+ public function removeCustomVariable()
+ {
+ $dbTable = $this->getDbTableName();
+ $index = $this->getHighestCustomVarIndex();
+
+ if ($index < 1) {
+ return null;
+ }
+
+ Db::exec(sprintf('ALTER TABLE %s DROP COLUMN custom_var_k%d', $dbTable, $index));
+ Db::exec(sprintf('ALTER TABLE %s DROP COLUMN custom_var_v%d', $dbTable, $index));
+
+ return $index;
+ }
+
+ public function addCustomVariable()
+ {
+ $dbTable = $this->getDbTableName();
+ $index = $this->getHighestCustomVarIndex() + 1;
+ $maxLen = CustomVariables::getMaxLengthCustomVariables();
+
+ Db::exec(sprintf('ALTER TABLE %s ADD COLUMN custom_var_k%d VARCHAR(%d) DEFAULT NULL', $dbTable, $index, $maxLen));
+ Db::exec(sprintf('ALTER TABLE %s ADD COLUMN custom_var_v%d VARCHAR(%d) DEFAULT NULL', $dbTable, $index, $maxLen));
+
+ return $index;
+ }
+
+ private function getDbTableName()
+ {
+ return Common::prefixTable($this->scope);
+ }
+
+ public static function getCustomVariableIndexFromFieldName($fieldName)
+ {
+ $onlyNumber = str_replace(array('custom_var_k', 'custom_var_v'), '', $fieldName);
+
+ if (is_numeric($onlyNumber)) {
+ return (int) $onlyNumber;
+ }
+ }
+
+ public static function getScopes()
+ {
+ return array(self::SCOPE_PAGE, self::SCOPE_VISIT, self::SCOPE_CONVERSION);
+ }
+
+ public static function install()
+ {
+ foreach (self::getScopes() as $scope) {
+ $model = new Model($scope);
+
+ try {
+ for ($index = 0; $index < 5; $index++) {
+ $model->addCustomVariable();
+ }
+ } catch (\Exception $e) {
+ Log::warning('Failed to add custom variable: ' . $e->getMessage());
+ }
+ }
+ }
+
+}
+
diff --git a/plugins/CustomVariables/tests/CustomVariablesTest.php b/plugins/CustomVariables/tests/CustomVariablesTest.php
new file mode 100644
index 0000000000..980401d608
--- /dev/null
+++ b/plugins/CustomVariables/tests/CustomVariablesTest.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\CustomVariables\tests;
+use Piwik\Plugins\CustomVariables\CustomVariables;
+use Piwik\Tracker\Cache;
+
+/**
+ * @group CustomVariables
+ * @group CustomVariablesTest
+ * @group Database
+ */
+class CustomVariablesTest extends \DatabaseTestCase
+{
+ public function testGetMaxCustomVariables_ShouldDetectCorrectNumberOfVariables()
+ {
+ Cache::clearCacheGeneral();
+ $this->assertSame(5, CustomVariables::getMaxCustomVariables());
+ }
+
+ public function testGetMaxCustomVariables_ShouldCacheTheResult()
+ {
+ CustomVariables::getMaxCustomVariables();
+ $cache = Cache::getCacheGeneral();
+
+ $this->assertSame(5, $cache['CustomVariables.MaxNumCustomVariables']);
+ }
+
+ public function testGetMaxCustomVariables_ShouldReadFromCacheIfPossible()
+ {
+ $cache = Cache::getCacheGeneral();
+ $cache['CustomVariables.MaxNumCustomVariables'] = 10;
+ Cache::setCacheGeneral($cache);
+
+ $this->assertSame(10, CustomVariables::getMaxCustomVariables());
+ }
+
+}
diff --git a/plugins/CustomVariables/tests/ModelTest.php b/plugins/CustomVariables/tests/ModelTest.php
new file mode 100644
index 0000000000..14d8647bf0
--- /dev/null
+++ b/plugins/CustomVariables/tests/ModelTest.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\CustomVariables\tests;
+use Piwik\Db;
+use Piwik\Plugins\CustomVariables\Model;
+
+/**
+ * @group CustomVariables
+ * @group ModelTest
+ * @group Database
+ */
+class ModelTest extends \DatabaseTestCase
+{
+ /**
+ * @expectedException \Exception
+ */
+ public function test_construct_shouldFailInCaseOfEmptyScope()
+ {
+ new Model(null);
+ }
+
+ /**
+ * @expectedException \Exception
+ */
+ public function test_construct_shouldFailInCaseOfInvalidScope()
+ {
+ new Model('inValId');
+ }
+
+ public function testGetAllScopes()
+ {
+ $this->assertEquals(array('log_link_visit_action', 'log_visit', 'log_conversion'), Model::getScopes());
+ }
+
+ public function testGetCustomVariableIndexFromFieldName()
+ {
+ $this->assertSame(0, Model::getCustomVariableIndexFromFieldName('custom_var_k0'));
+ $this->assertSame(0, Model::getCustomVariableIndexFromFieldName('custom_var_v0'));
+ $this->assertSame(5, Model::getCustomVariableIndexFromFieldName('custom_var_k5'));
+ $this->assertSame(5, Model::getCustomVariableIndexFromFieldName('custom_var_v5'));
+ $this->assertSame(938, Model::getCustomVariableIndexFromFieldName('custom_var_k938'));
+ $this->assertSame(938, Model::getCustomVariableIndexFromFieldName('custom_var_v938'));
+ $this->assertSame(null, Model::getCustomVariableIndexFromFieldName('otherfield'));
+ }
+
+ public function testGetScopeName()
+ {
+ $this->assertEquals('Page', $this->getPageScope()->getScopeName());
+ $this->assertEquals('Visit', $this->getVisitScope()->getScopeName());
+ $this->assertEquals('Conversion', $this->getConversionScope()->getScopeName());
+ }
+
+ public function test_getCurrentNumCustomVars()
+ {
+ $this->assertEquals(5, $this->getPageScope()->getCurrentNumCustomVars());
+ $this->assertEquals(5, $this->getVisitScope()->getCurrentNumCustomVars());
+ $this->assertEquals(5, $this->getConversionScope()->getCurrentNumCustomVars());
+
+ $this->getPageScope()->addCustomVariable();
+ $this->getConversionScope()->removeCustomVariable();
+
+ $this->assertEquals(6, $this->getPageScope()->getCurrentNumCustomVars());
+ $this->assertEquals(5, $this->getVisitScope()->getCurrentNumCustomVars());
+ $this->assertEquals(4, $this->getConversionScope()->getCurrentNumCustomVars());
+ }
+
+ public function test_getCustomVarIndexes()
+ {
+ $this->assertEquals(array(1,2,3,4,5), $this->getPageScope()->getCustomVarIndexes());
+ $this->assertEquals(array(1,2,3,4,5), $this->getVisitScope()->getCustomVarIndexes());
+ $this->assertEquals(array(1,2,3,4,5), $this->getConversionScope()->getCustomVarIndexes());
+
+ $this->getPageScope()->addCustomVariable();
+ $this->getConversionScope()->removeCustomVariable();
+
+ $this->assertEquals(array(1,2,3,4,5,6), $this->getPageScope()->getCustomVarIndexes());
+ $this->assertEquals(array(1,2,3,4,5), $this->getVisitScope()->getCustomVarIndexes());
+ $this->assertEquals(array(1,2,3,4), $this->getConversionScope()->getCustomVarIndexes());
+ }
+
+ public function test_getHighestCustomVarIndex_addCustomVariable_removeCustomVariable()
+ {
+ $this->assertEquals(5, $this->getPageScope()->getHighestCustomVarIndex());
+ $this->assertEquals(5, $this->getVisitScope()->getHighestCustomVarIndex());
+ $this->assertEquals(5, $this->getConversionScope()->getHighestCustomVarIndex());
+
+ $this->getPageScope()->addCustomVariable();
+ $this->getConversionScope()->removeCustomVariable();
+
+ $this->assertEquals(6, $this->getPageScope()->getHighestCustomVarIndex());
+ $this->assertEquals(5, $this->getVisitScope()->getHighestCustomVarIndex());
+ $this->assertEquals(4, $this->getConversionScope()->getHighestCustomVarIndex());
+
+ $this->getConversionScope()->removeCustomVariable();
+ $this->getPageScope()->addCustomVariable();
+ $this->getVisitScope()->addCustomVariable();
+ $this->getPageScope()->addCustomVariable();
+ $this->getConversionScope()->removeCustomVariable();
+
+ $this->assertEquals(8, $this->getPageScope()->getHighestCustomVarIndex());
+ $this->assertEquals(6, $this->getVisitScope()->getHighestCustomVarIndex());
+ $this->assertEquals(2, $this->getConversionScope()->getHighestCustomVarIndex());
+ }
+
+ public function test_removeCustomVariable_shouldNotFailIfRemovesMoreThanExist()
+ {
+ $scope = $this->getPageScope();
+
+ $this->assertEquals(5, $scope->getHighestCustomVarIndex());
+
+ for ($index = 0; $index < 5; $index++) {
+ $scope->removeCustomVariable();
+ $this->assertEquals(4 - $index, $scope->getHighestCustomVarIndex());
+ }
+
+ $this->assertNull($scope->removeCustomVariable());
+ $this->assertEquals(0, $scope->getHighestCustomVarIndex());
+ $this->assertEquals(0, $scope->getCurrentNumCustomVars());
+ }
+
+ public function test_removeCustomVariable_addCustomVariable_ReturnsIndex()
+ {
+ $scopeToAdd = $this->getPageScope();
+ $scopeToRemove = $this->getVisitScope();
+
+ for ($index = 0; $index < 5; $index++) {
+ $this->assertEquals(5 - $index, $scopeToRemove->removeCustomVariable());
+ $this->assertEquals(6 + $index, $scopeToAdd->addCustomVariable());
+ }
+ }
+
+ private function getPageScope()
+ {
+ return new Model(Model::SCOPE_PAGE);
+ }
+
+ private function getVisitScope()
+ {
+ return new Model(Model::SCOPE_VISIT);
+ }
+
+ private function getConversionScope()
+ {
+ return new Model(Model::SCOPE_CONVERSION);
+ }
+
+
+}
diff --git a/plugins/Dashboard/javascripts/dashboardObject.js b/plugins/Dashboard/javascripts/dashboardObject.js
index 86af47f54f..ccdde5051c 100644
--- a/plugins/Dashboard/javascripts/dashboardObject.js
+++ b/plugins/Dashboard/javascripts/dashboardObject.js
@@ -400,7 +400,6 @@
$('object', this).show();
$('.widgetHover', this).removeClass('widgetHover');
$('.widgetTopHover', this).removeClass('widgetTopHover');
- $('.button#close, .button#maximise', this).hide();
if ($('.widget:has(".piwik-graph")', ui.item).length) {
reloadWidget($('.widget', ui.item).attr('id'));
}
diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php
index ba8a68efed..2d64135948 100644
--- a/plugins/Goals/Controller.php
+++ b/plugins/Goals/Controller.php
@@ -145,7 +145,7 @@ class Controller extends \Piwik\Plugin\Controller
$view->topDimensions = $this->getTopDimensions($idGoal);
// conversion rate for new and returning visitors
- $segment = urldecode(\Piwik\Plugins\VisitFrequency\Archiver::RETURNING_VISITOR_SEGMENT);
+ $segment = urldecode(\Piwik\Plugins\VisitFrequency\API::RETURNING_VISITOR_SEGMENT);
$conversionRateReturning = API::getInstance()->getConversionRate($this->idSite, Common::getRequestVar('period'), Common::getRequestVar('date'), $segment, $idGoal);
$view->conversion_rate_returning = $this->formatConversionRate($conversionRateReturning);
$segment = 'visitorType==new';
diff --git a/plugins/Live/Visitor.php b/plugins/Live/Visitor.php
index 75b54e383b..9e13d9b514 100644
--- a/plugins/Live/Visitor.php
+++ b/plugins/Live/Visitor.php
@@ -16,6 +16,7 @@ use Piwik\Db;
use Piwik\IP;
use Piwik\Piwik;
use Piwik\Plugins\API\API as APIMetadata;
+use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Plugins\Referrers\API as APIReferrers;
use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
use Piwik\Tracker\Action;
@@ -338,10 +339,13 @@ class Visitor
function getCustomVariables()
{
$customVariables = array();
- for ($i = 1; $i <= Tracker::MAX_CUSTOM_VARIABLES; $i++) {
+
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
if (!empty($this->details['custom_var_k' . $i])) {
$customVariables[$i] = array(
- 'customVariableName' . $i => $this->details['custom_var_k' . $i],
+ 'customVariableName' . $i => $this->details['custom_var_k' . $i],
'customVariableValue' . $i => $this->details['custom_var_v' . $i],
);
}
@@ -723,8 +727,10 @@ class Visitor
{
$idVisit = $visitorDetailsArray['idVisit'];
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+
$sqlCustomVariables = '';
- for ($i = 1; $i <= Tracker::MAX_CUSTOM_VARIABLES; $i++) {
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
$sqlCustomVariables .= ', custom_var_k' . $i . ', custom_var_v' . $i;
}
// The second join is a LEFT join to allow returning records that don't have a matching page title
@@ -761,7 +767,10 @@ class Visitor
foreach ($actionDetails as $actionIdx => &$actionDetail) {
$actionDetail =& $actionDetails[$actionIdx];
$customVariablesPage = array();
- for ($i = 1; $i <= Tracker::MAX_CUSTOM_VARIABLES; $i++) {
+
+ $maxCustomVariables = CustomVariables::getMaxCustomVariables();
+
+ for ($i = 1; $i <= $maxCustomVariables; $i++) {
if (!empty($actionDetail['custom_var_k' . $i])) {
$cvarKey = $actionDetail['custom_var_k' . $i];
$cvarKey = static::getCustomVariablePrettyKey($cvarKey);
diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php
index 6bbab8de7e..3baf42679e 100644
--- a/plugins/SitesManager/API.php
+++ b/plugins/SitesManager/API.php
@@ -24,6 +24,7 @@ use Piwik\TaskScheduler;
use Piwik\Tracker\Cache;
use Piwik\Url;
use Piwik\UrlHelper;
+use Piwik\ProxyHttp;
/**
* The SitesManager API gives you full control on Websites in Piwik (create, update and delete), and many methods to retrieve websites based on various attributes.
@@ -71,7 +72,10 @@ class API extends \Piwik\Plugin\API
* @internal param $
* @return string The Javascript tag ready to be included on the HTML pages
*/
- public function getJavascriptTag($idSite, $piwikUrl = '', $mergeSubdomains = false, $groupPageTitlesByDomain = false, $mergeAliasUrls = false, $visitorCustomVariables = false, $pageCustomVariables = false, $customCampaignNameQueryParam = false, $customCampaignKeywordParam = false, $doNotTrack = false)
+ public function getJavascriptTag($idSite, $piwikUrl = '', $mergeSubdomains = false, $groupPageTitlesByDomain = false,
+ $mergeAliasUrls = false, $visitorCustomVariables = false, $pageCustomVariables = false,
+ $customCampaignNameQueryParam = false, $customCampaignKeywordParam = false,
+ $doNotTrack = false)
{
Piwik::checkUserHasViewAccess($idSite);
@@ -80,12 +84,57 @@ class API extends \Piwik\Plugin\API
}
$piwikUrl = Common::sanitizeInputValues($piwikUrl);
- $htmlEncoded = Piwik::getJavascriptCode($idSite, $piwikUrl, $mergeSubdomains, $groupPageTitlesByDomain, $mergeAliasUrls, $visitorCustomVariables, $pageCustomVariables, $customCampaignNameQueryParam, $customCampaignKeywordParam, $doNotTrack);
+ $htmlEncoded = Piwik::getJavascriptCode($idSite, $piwikUrl, $mergeSubdomains, $groupPageTitlesByDomain,
+ $mergeAliasUrls, $visitorCustomVariables, $pageCustomVariables,
+ $customCampaignNameQueryParam, $customCampaignKeywordParam,
+ $doNotTrack);
$htmlEncoded = str_replace(array('<br>', '<br />', '<br/>'), '', $htmlEncoded);
return $htmlEncoded;
}
/**
+ * Returns image link tracking code for a given site with specified options.
+ *
+ * @param int $idSite The ID to generate tracking code for.
+ * @param string $piwikUrl The domain and URL path to the Piwik installation.
+ * @param int $idGoal An ID for a goal to trigger a conversion for.
+ * @param int $revenue The revenue of the goal conversion. Only used if $idGoal is supplied.
+ * @return string The HTML tracking code.
+ */
+ public function getImageTrackingCode($idSite, $piwikUrl = '', $actionName = false, $idGoal = false, $revenue = false)
+ {
+ $urlParams = array('idSite' => $idSite, 'rec' => 1);
+
+ if ($actionName !== false) {
+ $urlParams['action_name'] = urlencode(Common::unsanitizeInputValue($actionName));
+ }
+
+ if ($idGoal !== false) {
+ $urlParams['idGoal'] = $idGoal;
+ if ($revenue !== false) {
+ $urlParams['revenue'] = $revenue;
+ }
+ }
+
+ /**
+ * Triggered when generating image link tracking code server side. Plugins can use
+ * this event to customise the image tracking code that is displayed to the
+ * user.
+ *
+ * @param string &$piwikHost The domain and URL path to the Piwik installation, eg,
+ * `'examplepiwik.com/path/to/piwik'`.
+ * @param array &$urlParams The query parameters used in the <img> element's src
+ * URL. See Piwik's image tracking docs for more info.
+ */
+ Piwik::postEvent('SitesManager.getImageTrackingCode', array(&$piwikUrl, &$urlParams));
+
+ $piwikUrl = (ProxyHttp::isHttps() ? "https://" : "http://") . $piwikUrl . '/piwik.php';
+ return "<!-- Piwik Image Tracker-->
+<img src=\"$piwikUrl?" . Url::getQueryStringFromParameters($urlParams) . "\" style=\"border:0\" alt=\"\" />
+<!-- End Piwik -->";
+ }
+
+ /**
* Returns all websites belonging to the specified group
* @param string $group Group name
* @return array of sites
diff --git a/plugins/VisitFrequency/API.php b/plugins/VisitFrequency/API.php
index 4c0f724398..e837fee01d 100644
--- a/plugins/VisitFrequency/API.php
+++ b/plugins/VisitFrequency/API.php
@@ -15,6 +15,7 @@ use Piwik\Common;
use Piwik\Archive;
use Piwik\SegmentExpression;
use Piwik\SettingsPiwik;
+use Piwik\Plugins\VisitsSummary\API as APIVisitsSummary;
/**
* VisitFrequency API lets you access a list of metrics related to Returning Visitors.
@@ -22,86 +23,62 @@ use Piwik\SettingsPiwik;
*/
class API extends \Piwik\Plugin\API
{
+ // visitorType==returning,visitorType==returningCustomer
+ const RETURNING_VISITOR_SEGMENT = "visitorType%3D%3Dreturning%2CvisitorType%3D%3DreturningCustomer";
+ const COLUMN_SUFFIX = "_returning";
+
+ /**
+ * @param int $idSite
+ * @param string $period
+ * @param string $date
+ * @param bool|string $segment
+ * @param bool|array $columns
+ * @return mixed
+ */
public function get($idSite, $period, $date, $segment = false, $columns = false)
{
- $archive = Archive::build($idSite, $period, $date, $segment);
-
- // array values are comma separated
- $columns = Piwik::getArrayFromApiParameter($columns);
- $tempColumns = array();
-
- $bounceRateReturningRequested = $averageVisitDurationReturningRequested = $actionsPerVisitReturningRequested = false;
- if (!empty($columns)) {
- // make sure base metrics are there for processed metrics
- if (false !== ($bounceRateReturningRequested = array_search('bounce_rate_returning', $columns))) {
- if (!in_array('nb_visits_returning', $columns)) {
- $tempColumns[] = 'nb_visits_returning';
- }
-
- if (!in_array('bounce_count_returning', $columns)) {
- $tempColumns[] = 'bounce_count_returning';
- }
-
- unset($columns[$bounceRateReturningRequested]);
- }
-
- if (false !== ($actionsPerVisitReturningRequested = array_search('nb_actions_per_visit_returning', $columns))) {
- if (!in_array('nb_actions_returning', $columns)) {
- $tempColumns[] = 'nb_actions_returning';
- }
-
- if (!in_array('nb_visits_returning', $columns)) {
- $tempColumns[] = 'nb_visits_returning';
- }
-
- unset($columns[$actionsPerVisitReturningRequested]);
- }
-
- if (false !== ($averageVisitDurationReturningRequested = array_search('avg_time_on_site_returning', $columns))) {
- if (!in_array('sum_visit_length_returning', $columns)) {
- $tempColumns[] = 'sum_visit_length_returning';
- }
-
- if (!in_array('nb_visits_returning', $columns)) {
- $tempColumns[] = 'nb_visits_returning';
- }
-
- unset($columns[$averageVisitDurationReturningRequested]);
- }
+ $segment = $this->appendReturningVisitorSegment($segment);
+
+ $this->unprefixColumns($columns);
+ $params = array(
+ 'idSite' => $idSite,
+ 'period' => $period,
+ 'date' => $date,
+ 'segment' => $segment,
+ 'columns' => implode(',', $columns),
+ 'format' => 'original',
+ 'serialize' => 0 // tests set this to 1
+ );
+ $table = Request::processRequest('VisitsSummary.get', $params);
+ $this->prefixColumns($table, $period);
+ return $table;
+ }
- $tempColumns = array_unique($tempColumns);
- $columns = array_merge($columns, $tempColumns);
+ protected function appendReturningVisitorSegment($segment)
+ {
+ if (empty($segment)) {
+ $segment = '';
} else {
- $bounceRateReturningRequested = $averageVisitDurationReturningRequested = $actionsPerVisitReturningRequested = true;
- $columns = array(
- 'nb_visits_returning',
- 'nb_actions_returning',
- 'nb_visits_converted_returning',
- 'bounce_count_returning',
- 'sum_visit_length_returning',
- 'max_actions_returning',
- );
-
- if (SettingsPiwik::isUniqueVisitorsEnabled($period)) {
- $columns = array_merge(array('nb_uniq_visitors_returning'), $columns);
- }
+ $segment .= urlencode(SegmentExpression::AND_DELIMITER);
}
- $dataTable = $archive->getDataTableFromNumeric($columns);
+ $segment .= self::RETURNING_VISITOR_SEGMENT;
+ return $segment;
+ }
- // Process ratio metrics
- if ($bounceRateReturningRequested !== false) {
- $dataTable->filter('ColumnCallbackAddColumnPercentage', array('bounce_rate_returning', 'bounce_count_returning', 'nb_visits_returning', 0));
- }
- if ($actionsPerVisitReturningRequested !== false) {
- $dataTable->filter('ColumnCallbackAddColumnQuotient', array('nb_actions_per_visit_returning', 'nb_actions_returning', 'nb_visits_returning', 1));
- }
- if ($averageVisitDurationReturningRequested !== false) {
- $dataTable->filter('ColumnCallbackAddColumnQuotient', array('avg_time_on_site_returning', 'sum_visit_length_returning', 'nb_visits_returning', 0));
+ protected function unprefixColumns(&$columns)
+ {
+ $columns = Piwik::getArrayFromApiParameter($columns);
+ foreach ($columns as &$column) {
+ $column = str_replace(self::COLUMN_SUFFIX, "", $column);
}
+ }
- // remove temporary metrics that were used to compute processed metrics
- $dataTable->deleteColumns($tempColumns);
-
- return $dataTable;
+ protected function prefixColumns($table, $period)
+ {
+ $rename = array();
+ foreach (APIVisitsSummary::getInstance()->getColumns($period) as $oldColumn) {
+ $rename[$oldColumn] = $oldColumn . self::COLUMN_SUFFIX;
+ }
+ $table->filter('ReplaceColumnNames', array($rename));
}
} \ No newline at end of file
diff --git a/plugins/VisitFrequency/Archiver.php b/plugins/VisitFrequency/Archiver.php
deleted file mode 100644
index b6f9913346..0000000000
--- a/plugins/VisitFrequency/Archiver.php
+++ /dev/null
@@ -1,131 +0,0 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-namespace Piwik\Plugins\VisitFrequency;
-
-use Piwik\ArchiveProcessor;
-use Piwik\ArchiveProcessor\Parameters as ArchiveProcessorParams;
-use Piwik\DataAccess\LogAggregator;
-use Piwik\API\Request;
-use Piwik\Piwik;
-use Piwik\Segment;
-use Piwik\SegmentExpression;
-use Piwik\Plugins\VisitsSummary\API as APIVisitsSummary;
-use Piwik\SettingsPiwik;
-use Piwik\Metrics;
-
-/**
- * Introduced to provide backwards compatibility for pre-2.0 data. Uses a segment to archive
- * data for day periods and aggregates this data for non-day periods.
- *
- * We normally would want to just forward requests to the VisitsSummary API w/ the correctly
- * modified segment, but in order to combine pre-2.0 data with post-2.0 data, there has
- * to be a VisitFrequency Archiver. Otherwise, the VisitsSummary metrics archiving will
- * be called, and the pre-2.0 VisitFrequency data (which is not retrieved by VisitsSummary) will
- * be ignored.
- */
-class Archiver extends \Piwik\Plugin\Archiver
-{
- // visitorType==returning,visitorType==returningCustomer
- const RETURNING_VISITOR_SEGMENT = "visitorType%3D%3Dreturning%2CvisitorType%3D%3DreturningCustomer";
- const COLUMN_SUFFIX = "_returning";
-
- public static $visitFrequencyPeriodMetrics = array(
- 'nb_visits_returning',
- 'nb_actions_returning',
- 'max_actions_returning',
- 'sum_visit_length_returning',
- 'bounce_count_returning',
- 'nb_visits_converted_returning'
- );
-
- public function aggregateDayReport()
- {
- $this->callVisitsSummaryApiAndArchive();
- }
-
- public function aggregateMultipleReports()
- {
- if (SettingsPiwik::isUniqueVisitorsEnabled($this->getProcessor()->getParams()->getPeriod()->getLabel())) {
- $this->computeUniqueVisitsForNonDay();
- }
-
- $this->getProcessor()->aggregateNumericMetrics(self::$visitFrequencyPeriodMetrics);
- }
-
- private function callVisitsSummaryApiAndArchive($columns = false)
- {
- $archiveParams = $this->getProcessor()->getParams();
- $periodLabel = $archiveParams->getPeriod()->getLabel();
-
- $params = array(
- 'idSite' => $archiveParams->getSite()->getId(),
- 'period' => $periodLabel,
- 'date' => $archiveParams->getPeriod()->getDateStart()->toString(),
- 'segment' => $this->appendReturningVisitorSegment($archiveParams->getSegment()->getString()),
- 'format' => 'original',
- 'serialize' => 0 // make sure we don't serialize (in case serialize is in the query parameters)
- );
- if ($columns) {
- $params['columns'] = implode(",", $columns);
- }
-
- $table = Request::processRequest('VisitsSummary.get', $params);
- $this->suffixColumns($table, $periodLabel);
-
- if ($table->getRowsCount() > 0) {
- $this->getProcessor()->insertNumericRecords($table->getFirstRow()->getColumns());
- }
- }
-
- private function computeUniqueVisitsForNonDay()
- {
- // NOTE: we cannot call the VisitsSummary API from within period archiving for some reason. it results in
- // a very hard to trace bug that breaks the OmniFixture severely (causes lots of data to not be shown).
- // no idea why it causes such an error.
- $oldParams = $this->getProcessor()->getParams();
- $site = $oldParams->getSite();
- $newSegment = $this->appendReturningVisitorSegment($oldParams->getSegment()->getString());
- $newParams = new ArchiveProcessorParams($site, $oldParams->getPeriod(), new Segment($newSegment, array($site->getId())));
-
- $logAggregator = new LogAggregator($newParams);
- $query = $logAggregator->queryVisitsByDimension(array(), false, array(), array(Metrics::INDEX_NB_UNIQ_VISITORS));
- $data = $query->fetch();
- $nbUniqVisitors = (float)$data[Metrics::INDEX_NB_UNIQ_VISITORS];
-
- $this->getProcessor()->insertNumericRecord('nb_uniq_visitors_returning', $nbUniqVisitors);
- }
-
- protected function appendReturningVisitorSegment($segment)
- {
- if (empty($segment)) {
- $segment = '';
- } else {
- $segment .= urlencode(SegmentExpression::AND_DELIMITER);
- }
- $segment .= self::RETURNING_VISITOR_SEGMENT;
- return $segment;
- }
-
- protected function unsuffixColumns(&$columns)
- {
- $columns = Piwik::getArrayFromApiParameter($columns);
- foreach ($columns as &$column) {
- $column = str_replace(self::COLUMN_SUFFIX, "", $column);
- }
- }
-
- protected function suffixColumns($table, $period)
- {
- $rename = array();
- foreach (APIVisitsSummary::getInstance()->getColumns($period) as $oldColumn) {
- $rename[$oldColumn] = $oldColumn . self::COLUMN_SUFFIX;
- }
- $table->filter('ReplaceColumnNames', array($rename));
- }
-} \ No newline at end of file
diff --git a/plugins/Zeitgeist/templates/javascriptCode.tpl b/plugins/Zeitgeist/templates/javascriptCode.tpl
index 104e39cbbf..488f39d00c 100644
--- a/plugins/Zeitgeist/templates/javascriptCode.tpl
+++ b/plugins/Zeitgeist/templates/javascriptCode.tpl
@@ -10,7 +10,6 @@
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript';
g.defer=true; g.async=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
-
</script>
<noscript><p><img src="http://{$piwikUrl}/piwik.php?idsite={$idSite}" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
diff --git a/tests/PHPUnit/Core/DeprecatedMethodsTest.php b/tests/PHPUnit/Core/DeprecatedMethodsTest.php
index bdcf46db8d..786b968d0e 100644
--- a/tests/PHPUnit/Core/DeprecatedMethodsTest.php
+++ b/tests/PHPUnit/Core/DeprecatedMethodsTest.php
@@ -22,7 +22,6 @@ class DeprecatedMethodsTest extends PHPUnit_Framework_TestCase
public function test_version2_0_4()
{
$validTill = '2014-04-01';
-
$this->assertDeprecatedMethodIsRemoved('\Piwik\Piwik', 'isUserIsSuperUserOrTheUser', $validTill);
$this->assertDeprecatedMethodIsRemoved('\Piwik\Piwik', 'checkUserIsSuperUserOrTheUser', $validTill);
$this->assertDeprecatedMethodIsRemoved('\Piwik\Piwik', 'isUserIsSuperUser', $validTill);
@@ -37,6 +36,8 @@ class DeprecatedMethodsTest extends PHPUnit_Framework_TestCase
$this->assertDeprecatedMethodIsRemoved('\FakeAccess', 'checkUserIsSuperUser', $validTill);
$this->assertDeprecatedMethodIsRemoved('\FakeAccess', 'setSuperUser', $validTill);
$this->assertDeprecatedMethodIsRemoved('\FakeAccess', 'getSuperUserLogin', $validTill);
+
+ $validTill = '2014-10-01';
$this->assertDeprecatedMethodIsRemoved('\Piwik\Config', 'getConfigSuperUserForBackwardCompatibility', $validTill);
}
diff --git a/tests/PHPUnit/Core/ReleaseCheckListTest.php b/tests/PHPUnit/Core/ReleaseCheckListTest.php
index 139d528819..fdcd0cce0c 100644
--- a/tests/PHPUnit/Core/ReleaseCheckListTest.php
+++ b/tests/PHPUnit/Core/ReleaseCheckListTest.php
@@ -14,6 +14,7 @@ class ReleaseCheckListTest extends PHPUnit_Framework_TestCase
public function setUp()
{
$this->globalConfig = _parse_ini_file(PIWIK_PATH_TEST_TO_ROOT . '/config/global.ini.php', true);
+
parent::setUp();
}
/**
@@ -88,8 +89,11 @@ class ReleaseCheckListTest extends PHPUnit_Framework_TestCase
require_once PIWIK_INCLUDE_PATH . "/core/TaskScheduler.php";
$this->assertFalse(DEBUG_FORCE_SCHEDULED_TASKS);
- require_once PIWIK_INCLUDE_PATH . "/core/API/ResponseBuilder.php";
- $this->assertFalse(\Piwik\API\ResponseBuilder::DISPLAY_BACKTRACE_DEBUG);
+
+ // Check the index.php has "backtrace disabled"
+ $content = file_get_contents(PIWIK_INCLUDE_PATH . "/index.php");
+ $expected = "define('PIWIK_PRINT_ERROR_BACKTRACE', false);";
+ $this->assertTrue( false !== strpos($content, $expected), 'index.php should contain: ' . $expected);
}
private function _checkEqual($key, $valueExpected)
@@ -148,19 +152,7 @@ class ReleaseCheckListTest extends PHPUnit_Framework_TestCase
public function testPiwikTrackerDebugIsOff()
{
$this->assertTrue(!isset($GLOBALS['PIWIK_TRACKER_DEBUG']));
-
- $oldGet = $_GET;
- $_GET = array('idsite' => 1);
-
- // hiding echoed out message on empty request
- ob_start();
- include PIWIK_PATH_TEST_TO_ROOT . "/piwik.php";
- ob_end_clean();
-
- $_GET = $oldGet;
-
- $this->assertEquals(0, \Piwik\Config::getInstance()->Tracker['debug']);
- $this->assertTrue($GLOBALS['PIWIK_TRACKER_DEBUG'] === false);
+ $this->assertEquals(0, $this->globalConfig['Tracker']['debug']);
}
/**
diff --git a/tests/PHPUnit/FakeAccess.php b/tests/PHPUnit/FakeAccess.php
index 0b550d1744..9711dbffba 100644
--- a/tests/PHPUnit/FakeAccess.php
+++ b/tests/PHPUnit/FakeAccess.php
@@ -56,29 +56,11 @@ class FakeAccess
}
}
- /**
- * @see FakeAccess::checkUserHasSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- public function checkUserIsSuperUser()
- {
- self::checkUserHasSuperUserAccess();
- }
-
public static function setSuperUserAccess($bool = true)
{
self::$superUser = $bool;
}
- /**
- * @see FakeAccess::setSuperUserAccess()
- * @deprecated deprecated since version 2.0.4
- */
- public static function setSuperUser($bool = true)
- {
- self::setSuperUserAccess($bool);
- }
-
public static function reloadAccess()
{
}
@@ -188,11 +170,4 @@ class FakeAccess
return $result;
}
- /**
- * @deprecated deprecated since version 2.0.4
- */
- public function getSuperUserLogin()
- {
- return self::$superUserLogin;
- }
}
diff --git a/tests/PHPUnit/Integration/Core/DbTest.php b/tests/PHPUnit/Integration/Core/DbTest.php
new file mode 100644
index 0000000000..3a8c31e7e8
--- /dev/null
+++ b/tests/PHPUnit/Integration/Core/DbTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+use Piwik\Db;
+use Piwik\Common;
+
+/**
+ * Class Core_DbTest
+ *
+ * @group Core
+ */
+class Core_DbTest extends DatabaseTestCase
+{
+
+ public function test_getColumnNamesFromTable()
+ {
+ $this->assertColumnNames('access', array('login', 'idsite', 'access'));
+ $this->assertColumnNames('option', array('option_name', 'option_value', 'autoload'));
+ }
+
+ private function assertColumnNames($tableName, $expectedColumnNames)
+ {
+ $colmuns = Db::getColumnNamesFromTable(Common::prefixTable($tableName));
+
+ $this->assertEquals($expectedColumnNames, $colmuns);
+ }
+
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/Core/LogTest.php b/tests/PHPUnit/Integration/Core/LogTest.php
index 67e366404b..4e2fd72ecc 100644
--- a/tests/PHPUnit/Integration/Core/LogTest.php
+++ b/tests/PHPUnit/Integration/Core/LogTest.php
@@ -29,7 +29,7 @@ class Core_LogTest extends DatabaseTestCase
public static $expectedExceptionOutput = array(
'screen' => 'dummy error message<br />
<br />
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php',
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php',
'file' => '[Core_LogTest] LogTest.php(161): dummy error message
dummy backtrace',
'database' => '[Core_LogTest] LogTest.php(161): dummy error message
diff --git a/tests/PHPUnit/Integration/Core/PiwikTest.php b/tests/PHPUnit/Integration/Core/PiwikTest.php
index 7dc414972a..28e303f0f3 100644
--- a/tests/PHPUnit/Integration/Core/PiwikTest.php
+++ b/tests/PHPUnit/Integration/Core/PiwikTest.php
@@ -59,7 +59,6 @@ class Core_PiwikTest extends DatabaseTestCase
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript';
g.defer=true; g.async=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
-
&lt;/script&gt;
&lt;noscript&gt;&lt;p&gt;&lt;img src=&quot;http://localhost/piwik/piwik.php?idsite=1&quot; style=&quot;border:0;&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;&lt;/noscript&gt;
&lt;!-- End Piwik Code --&gt;
diff --git a/tests/PHPUnit/Core/SegmentTest.php b/tests/PHPUnit/Integration/Core/SegmentTest.php
index 1b272cc7a7..f0a313326a 100644
--- a/tests/PHPUnit/Core/SegmentTest.php
+++ b/tests/PHPUnit/Integration/Core/SegmentTest.php
@@ -9,7 +9,7 @@ use Piwik\Segment;
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-class SegmentTest extends PHPUnit_Framework_TestCase
+class SegmentTest extends DatabaseTestCase
{
public function setUp()
{
diff --git a/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referrers.getCleanKeyword.xml b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referrers.getCleanKeyword.xml
index 4f983c144f..3ad4041057 100644
--- a/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referrers.getCleanKeyword.xml
+++ b/tests/PHPUnit/Integration/expected/test_OneVisitorTwoVisits__Referrers.getCleanKeyword.xml
@@ -2,5 +2,5 @@
<result>
<error message="Please specify a value for 'label'.
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_day.xml b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_day.xml
index 2680f686f7..a0995fa6e9 100644
--- a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_day.xml
@@ -2,5 +2,5 @@
<result>
<error message="NoDataForAction
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_month.xml b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_month.xml
index 2680f686f7..a0995fa6e9 100644
--- a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageTitle_month.xml
@@ -2,5 +2,5 @@
<result>
<error message="NoDataForAction
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_day.xml b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_day.xml
index 2680f686f7..a0995fa6e9 100644
--- a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_day.xml
@@ -2,5 +2,5 @@
<result>
<error message="NoDataForAction
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_month.xml b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_month.xml
index 2680f686f7..a0995fa6e9 100644
--- a/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_month.xml
+++ b/tests/PHPUnit/Integration/expected/test_Transitions_noData__Transitions.getTransitionsForPageUrl_month.xml
@@ -2,5 +2,5 @@
<result>
<error message="NoDataForAction
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getRowEvolution_day.xml b/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getRowEvolution_day.xml
index ecdcd30b5b..29bf42cae8 100644
--- a/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getRowEvolution_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getRowEvolution_day.xml
@@ -2,5 +2,5 @@
<result>
<error message="Row evolutions can not be processed with this combination of \'date\' and \'period\' parameters.
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml b/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml
index a9f39502fb..3da4a2d812 100644
--- a/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml
+++ b/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata_year__SitesManager.getJavascriptTag.xml
@@ -11,7 +11,6 @@
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript';
g.defer=true; g.async=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
-
&lt;/script&gt;
&lt;noscript&gt;&lt;p&gt;&lt;img src=&quot;http://example.org/piwik/piwik.php?idsite=1&quot; style=&quot;border:0;&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;&lt;/noscript&gt;
&lt;!-- End Piwik Code --&gt;
diff --git a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_Metadata_Goals.Get_NotExistingGoal__API.getProcessedReport_day.xml b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_Metadata_Goals.Get_NotExistingGoal__API.getProcessedReport_day.xml
index 69a86c5da6..1625ba026c 100644
--- a/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_Metadata_Goals.Get_NotExistingGoal__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_ecommerceOrderWithItems_Metadata_Goals.Get_NotExistingGoal__API.getProcessedReport_day.xml
@@ -3,5 +3,5 @@
<error message="Requested report Goals.get for Website id=1 not found in the list of available reports.
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_day.xml b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_day.xml
index 06f6e4a797..64d7aebcb2 100644
--- a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_day.xml
@@ -2,5 +2,5 @@
<result>
<error message="Referrers.getAll with multiple sites or dates is not supported (yet).
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_week.xml b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_week.xml
index 06f6e4a797..64d7aebcb2 100644
--- a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_week.xml
+++ b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__Referrers.getAll_week.xml
@@ -2,5 +2,5 @@
<result>
<error message="Referrers.getAll with multiple sites or dates is not supported (yet).
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_day.xml b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_day.xml
index 9e698bf229..547baf7416 100644
--- a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_day.xml
+++ b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_day.xml
@@ -2,5 +2,5 @@
<result>
<error message="VisitTime.getByDayOfWeek does not support multiple dates.
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_week.xml b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_week.xml
index 9e698bf229..547baf7416 100644
--- a/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_week.xml
+++ b/tests/PHPUnit/Integration/expected/test_noVisit_PeriodIsLast__VisitTime.getByDayOfWeek_week.xml
@@ -2,5 +2,5 @@
<result>
<error message="VisitTime.getByDayOfWeek does not support multiple dates.
- --&gt; To temporarily debug this error further, set const DISPLAY_BACKTRACE_DEBUG=true; in ResponseBuilder.php" />
+ --&gt; To temporarily debug this error further, set const PIWIK_PRINT_ERROR_BACKTRACE=true; in index.php" />
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/UI b/tests/PHPUnit/UI
-Subproject 618333d794be0a8ad04c0106c0196fcc4f12d8d
+Subproject a878862448d37eafb1c3896cc97acc553aca1f7