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:
authormattpiwik <matthieu.aubry@gmail.com>2008-12-17 20:26:15 +0300
committermattpiwik <matthieu.aubry@gmail.com>2008-12-17 20:26:15 +0300
commit0c3ef698010708ba0484aabd5a01db3b62f47365 (patch)
treee1b592d7358d3a01a1dc39cd8c3134d5ee551b2f
parentfa3877ec785daf7d6aad35ca877611ff040c2ffd (diff)
- adding Goal Tracking related goodness in core, and plugins
- goal table icon below datatable that have goal segmentation - rss export icon below datatable - cleaning code, refactoring, renaming goodness - adding switch enable_detect_unique_visitor_using_settings that enables/disable heuristic based on config hash - refactoring how plugins handle archiving for more clarity git-svn-id: http://dev.piwik.org/svn/trunk@838 59fd770c-687e-43c8-a1e3-f5a4ff64c105
-rwxr-xr-xconfig/global.ini.php14
-rw-r--r--core/API/DataTableGenericFilter.php9
-rw-r--r--core/API/ResponseBuilder.php2
-rw-r--r--core/Access.php14
-rw-r--r--core/Archive.php486
-rw-r--r--core/Archive/Single.php3
-rw-r--r--core/ArchiveProcessing.php26
-rw-r--r--core/ArchiveProcessing/Day.php208
-rw-r--r--core/ArchiveProcessing/Period.php46
-rw-r--r--core/ArchiveProcessing/Record/BlobArray.php4
-rw-r--r--core/Common.php32
-rw-r--r--core/Controller.php10
-rw-r--r--core/DataTable.php18
-rw-r--r--core/DataTable/Filter.php3
-rw-r--r--core/DataTable/Filter/AddColumnsWhenShowAllColumns.php3
-rw-r--r--core/DataTable/Filter/AddSummaryRow.php2
-rw-r--r--core/DataTable/Filter/ExactMatch.php104
-rw-r--r--core/DataTable/Filter/ExcludeLowPopulation.php20
-rw-r--r--core/DataTable/Filter/ReplaceColumnNames.php31
-rw-r--r--core/DataTable/Filter/Sort.php56
-rw-r--r--core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php115
-rw-r--r--core/DataTable/Renderer/Csv.php21
-rw-r--r--core/DataTable/Renderer/Php.php2
-rw-r--r--core/DataTable/Renderer/Rss.php16
-rw-r--r--core/DataTable/Renderer/Xml.php19
-rw-r--r--core/DataTable/Row.php65
-rw-r--r--core/Date.php22
-rw-r--r--core/FrontController.php1
-rw-r--r--core/Period/Range.php1
-rw-r--r--core/Piwik.php29
-rw-r--r--core/Plugin.php9
-rw-r--r--core/SmartyPlugins/function.logoHtml.php32
-rw-r--r--core/SmartyPlugins/function.url.php62
-rw-r--r--core/Timer.php4
-rw-r--r--core/Tracker.php51
-rw-r--r--core/Tracker/Action.php130
-rw-r--r--core/Tracker/Generator.php3
-rw-r--r--core/Tracker/Generator/Tracker.php1
-rw-r--r--core/Tracker/Generator/Visit.php6
-rw-r--r--core/Tracker/GoalManager.php147
-rw-r--r--core/Tracker/Visit.php480
-rw-r--r--core/Updates/0.2.28.php9
-rw-r--r--core/Version.php2
-rw-r--r--core/View.php2
-rw-r--r--core/ViewDataTable.php142
-rw-r--r--core/ViewDataTable/Cloud.php6
-rw-r--r--core/ViewDataTable/GenerateGraphData/ChartEvolution.php384
-rw-r--r--core/ViewDataTable/GenerateGraphHTML.php14
-rw-r--r--core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php26
-rw-r--r--core/ViewDataTable/HtmlTable.php45
-rw-r--r--core/ViewDataTable/HtmlTable/AllColumns.php19
-rw-r--r--core/ViewDataTable/HtmlTable/Goals.php77
-rw-r--r--core/ViewDataTable/Sparkline.php21
-rw-r--r--core/Visualization/ChartEvolution.php152
-rw-r--r--misc/TODO37
-rw-r--r--misc/generateVisits.php8
-rw-r--r--piwik.php1
-rw-r--r--plugins/Actions/Actions.php591
-rw-r--r--plugins/Actions/Controller.php2
-rw-r--r--plugins/CoreHome/Controller.php104
-rw-r--r--plugins/CoreHome/templates/cloud.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable.css14
-rw-r--r--plugins/CoreHome/templates/datatable.js39
-rw-r--r--plugins/CoreHome/templates/datatable.tpl10
-rw-r--r--plugins/CoreHome/templates/datatable_actions.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable_actions_js.tpl6
-rw-r--r--plugins/CoreHome/templates/datatable_actions_recursive.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable_actions_subdatable.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable_footer.tpl16
-rw-r--r--plugins/CoreHome/templates/datatable_js.tpl6
-rw-r--r--plugins/CoreHome/templates/graph.tpl2
-rw-r--r--plugins/ExampleAPI/API.php1
-rw-r--r--plugins/ExamplePlugin/ExamplePlugin.php18
-rw-r--r--plugins/Installation/Controller.php952
-rw-r--r--plugins/Provider/API.php13
-rw-r--r--plugins/Provider/Controller.php4
-rw-r--r--plugins/Provider/Provider.php3
-rw-r--r--plugins/Referers/API.php4
-rw-r--r--plugins/Referers/Controller.php62
-rw-r--r--plugins/Referers/Referers.php238
-rw-r--r--plugins/Referers/functions.php3
-rw-r--r--plugins/Referers/templates/index.tpl (renamed from plugins/Referers/index.tpl)0
-rw-r--r--plugins/Referers/templates/searchEngines_Keywords.tpl (renamed from plugins/Referers/searchEngines_Keywords.tpl)0
-rw-r--r--plugins/UserCountry/Controller.php28
-rw-r--r--plugins/UserCountry/UserCountry.php43
-rw-r--r--plugins/UserSettings/UserSettings.php12
-rw-r--r--plugins/VisitFrequency/API.php6
-rw-r--r--plugins/VisitFrequency/Controller.php3
-rw-r--r--plugins/VisitFrequency/VisitFrequency.php5
-rw-r--r--plugins/VisitTime/Controller.php1
-rw-r--r--plugins/VisitTime/VisitTime.php47
-rw-r--r--plugins/VisitsSummary/API.php6
-rw-r--r--plugins/VisitsSummary/Controller.php1
-rw-r--r--tests/core/DataTable.test.php8
-rw-r--r--tests/core/DataTable/Renderer.test.php22
-rw-r--r--tests/core/Piwik.test.php5
-rw-r--r--tests/datasets/referer-xss.txt7
-rw-r--r--themes/default/common.css16
-rw-r--r--themes/default/images/feed.pngbin0 -> 691 bytes
-rw-r--r--themes/default/images/goal.pngbin0 -> 672 bytes
100 files changed, 3265 insertions, 2293 deletions
diff --git a/config/global.ini.php b/config/global.ini.php
index 4331a20df7..4cf9ad1006 100755
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -61,7 +61,6 @@ PluginsInstalled[] = Installation
[Plugins_Tracker]
-
[Debug]
; if set to true, the archiving process will always be triggered, even if the archive has already been computed
; this is useful when making changes to the archiving code so we can force the archiving process
@@ -98,6 +97,9 @@ enable_browser_archiving_triggering = true
; the page first-post in the subcategory development which belongs to the blog category
action_category_delimiter = /
+; currency used by default when reporting money in Piwik
+default_currency = "$"
+
; if you want all your users to use Piwik in only one language, disable the LanguagesManager
; plugin, and set this default_language (users won't see the language drop down)
default_language = en
@@ -152,6 +154,16 @@ campaign_keyword_var_name = piwik_kwd
; name of the cookie used to store the visitor information
cookie_name = piwik_visitor
+; if set to false, any goal conversion will be credited to the last more recent non empty referer.
+; when set to true, the first ever referer used to reach the website will be used
+use_first_referer_to_determine_goal_referer = false
+
+; if set to true, Piwik will try to match visitors without cookie to a previous visitor that has the same
+; configuration: OS, browser, resolution, IP, etc. This heuristic adds an extra SQL query for each page view without cookie.
+; it is advised to set it to true for more accurate detection of unique visitors.
+; However when most users have the same IP, and the same configuration, it is advised to set it to false
+enable_detect_unique_visitor_using_settings = false
+
[log]
;possible values for log: screen, database, file
diff --git a/core/API/DataTableGenericFilter.php b/core/API/DataTableGenericFilter.php
index bfe6367027..4304da0c40 100644
--- a/core/API/DataTableGenericFilter.php
+++ b/core/API/DataTableGenericFilter.php
@@ -42,13 +42,16 @@ class Piwik_API_DataTableGenericFilter
),
'ExcludeLowPopulation' => array(
'filter_excludelowpop' => array('string'),
- 'filter_excludelowpop_value'=> array('float'),
+ 'filter_excludelowpop_value'=> array('float', '0'),
),
'AddColumnsWhenShowAllColumns' => array(
'filter_add_columns_when_show_all_columns' => array('integer')
),
+ 'UpdateColumnsWhenShowAllGoals' => array(
+ 'filter_update_columns_when_show_all_goals' => array('integer')
+ ),
'Sort' => array(
- 'filter_sort_column' => array('string', 'nb_visits'),
+ 'filter_sort_column' => array('string', Piwik_Archive::INDEX_NB_VISITS),
'filter_sort_order' => array('string', Zend_Registry::get('config')->General->dataTable_default_sort_order),
),
'Limit' => array(
@@ -110,7 +113,7 @@ class Piwik_API_DataTableGenericFilter
break;
}
}
-
+
if(!$exceptionRaised)
{
// a generic filter class name must follow this pattern
diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php
index 2a97febdb0..f0455c95c9 100644
--- a/core/API/ResponseBuilder.php
+++ b/core/API/ResponseBuilder.php
@@ -245,7 +245,7 @@ class Piwik_API_ResponseBuilder
protected function handleDataTable($datatable)
{
// if the flag disable_generic_filters is defined we skip the generic filters
- if(Piwik_Common::getRequestVar('disable_generic_filters', 'false', 'string', $this->request) == 'false')
+ if('false' == Piwik_Common::getRequestVar('disable_generic_filters', 'false', 'string', $this->request))
{
$genericFilter = new Piwik_API_DataTableGenericFilter($datatable, $this->request);
$genericFilter->filter();
diff --git a/core/Access.php b/core/Access.php
index f6251ec2a1..36a91f5c77 100644
--- a/core/Access.php
+++ b/core/Access.php
@@ -253,7 +253,6 @@ class Piwik_Access
/**
* If the user doesn't have an ADMIN access for at least one website, throws an exception
- *
* @throws Exception
*/
public function checkUserHasSomeAdminAccess()
@@ -264,6 +263,19 @@ class Piwik_Access
throw new Piwik_Access_NoAccessException("You can't access this resource as it requires an 'admin' access for at least one website.");
}
}
+
+ /**
+ * If the user doesn't have any view permission, throw exception
+ * @throws Exception
+ */
+ public function checkUserHasSomeViewAccess()
+ {
+ $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
+ if(count($idSitesAccessible) == 0)
+ {
+ throw new Piwik_Access_NoAccessException("You can't access this resource as it requires a 'view' access for at least one website.");
+ }
+ }
/**
* This method checks that the user has ADMIN access for the given list of websites.
diff --git a/core/Archive.php b/core/Archive.php
index b06bc11891..f6ca63c2b6 100644
--- a/core/Archive.php
+++ b/core/Archive.php
@@ -1,255 +1,273 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: Archive.php 585 2008-07-28 00:56:50Z matt $
- *
- * @package Piwik
- */
-
-require_once 'Period.php';
-require_once 'Date.php';
-require_once 'ArchiveProcessing.php';
-require_once 'Archive/Single.php';
-
-/**
- * The archive object is used to query specific data for a day or a period of statistics for a given website.
- *
- * Example:
- * <pre>
- * $archive = Piwik_Archive::build($idSite = 1, $period = 'week', '2008-03-08' );
- * $dataTable = $archive->getDataTable('Provider_hostnameExt');
- * $dataTable->queueFilter('Piwik_DataTable_Filter_ReplaceColumnNames');
- * return $dataTable;
- * </pre>
- *
- * Example bis:
- * <pre>
- * $archive = Piwik_Archive::build($idSite = 3, $period = 'day', $date = 'today' );
- * $nbVisits = $archive->getNumeric('nb_visits');
- * return $nbVisits;
- * </pre>
- *
- * If the requested statistics are not yet processed, Archive uses ArchiveProcessing to archive the statistics.
- *
- * @package Piwik
- * @subpackage Piwik_Archive
- */
-abstract class Piwik_Archive
-{
- /**
- * When saving DataTables in the DB, we sometimes replace the columns name by these IDs so we save up lots of bytes
- * Eg. INDEX_NB_UNIQ_VISITORS is an integer: 4 bytes, but 'nb_uniq_visitors' is 16 bytes at least
- * (in php it's actually even much more)
- *
- */
- const INDEX_NB_UNIQ_VISITORS = 1;
- const INDEX_NB_VISITS = 2;
- const INDEX_NB_ACTIONS = 3;
- const INDEX_MAX_ACTIONS = 4;
- const INDEX_SUM_VISIT_LENGTH = 5;
- const INDEX_BOUNCE_COUNT = 6;
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Archive.php 585 2008-07-28 00:56:50Z matt $
+ *
+ * @package Piwik
+ */
- /*
- * Integer indexed column name => string indexed column name
+require_once 'Period.php';
+require_once 'Date.php';
+require_once 'ArchiveProcessing.php';
+require_once 'Archive/Single.php';
+
+/**
+ * The archive object is used to query specific data for a day or a period of statistics for a given website.
+ *
+ * Example:
+ * <pre>
+ * $archive = Piwik_Archive::build($idSite = 1, $period = 'week', '2008-03-08' );
+ * $dataTable = $archive->getDataTable('Provider_hostnameExt');
+ * $dataTable->queueFilter('Piwik_DataTable_Filter_ReplaceColumnNames');
+ * return $dataTable;
+ * </pre>
+ *
+ * Example bis:
+ * <pre>
+ * $archive = Piwik_Archive::build($idSite = 3, $period = 'day', $date = 'today' );
+ * $nbVisits = $archive->getNumeric('nb_visits');
+ * return $nbVisits;
+ * </pre>
+ *
+ * If the requested statistics are not yet processed, Archive uses ArchiveProcessing to archive the statistics.
+ *
+ * @package Piwik
+ * @subpackage Piwik_Archive
+ */
+abstract class Piwik_Archive
+{
+ /**
+ * When saving DataTables in the DB, we sometimes replace the columns name by these IDs so we save up lots of bytes
+ * Eg. INDEX_NB_UNIQ_VISITORS is an integer: 4 bytes, but 'nb_uniq_visitors' is 16 bytes at least
+ * (in php it's actually even much more)
+ *
*/
+ const INDEX_NB_UNIQ_VISITORS = 1;
+ const INDEX_NB_VISITS = 2;
+ const INDEX_NB_ACTIONS = 3;
+ const INDEX_MAX_ACTIONS = 4;
+ const INDEX_SUM_VISIT_LENGTH = 5;
+ const INDEX_BOUNCE_COUNT = 6;
+ const INDEX_NB_VISITS_CONVERTED = 7;
+ const INDEX_NB_CONVERSIONS = 8;
+ const INDEX_REVENUE = 9;
+ const INDEX_GOALS = 10;
+
+ const INDEX_GOAL_NB_CONVERSIONS = 1;
+ const INDEX_GOAL_REVENUE = 2;
+
public static $mappingFromIdToName = array(
- Piwik_Archive::INDEX_NB_UNIQ_VISITORS => 'nb_uniq_visitors',
- Piwik_Archive::INDEX_NB_VISITS => 'nb_visits',
- Piwik_Archive::INDEX_NB_ACTIONS => 'nb_actions',
- Piwik_Archive::INDEX_MAX_ACTIONS => 'max_actions',
- Piwik_Archive::INDEX_SUM_VISIT_LENGTH => 'sum_visit_length',
- Piwik_Archive::INDEX_BOUNCE_COUNT => 'bounce_count',
+ Piwik_Archive::INDEX_NB_UNIQ_VISITORS => 'nb_uniq_visitors',
+ Piwik_Archive::INDEX_NB_VISITS => 'nb_visits',
+ Piwik_Archive::INDEX_NB_ACTIONS => 'nb_actions',
+ Piwik_Archive::INDEX_MAX_ACTIONS => 'max_actions',
+ Piwik_Archive::INDEX_SUM_VISIT_LENGTH => 'sum_visit_length',
+ Piwik_Archive::INDEX_BOUNCE_COUNT => 'bounce_count',
+ Piwik_Archive::INDEX_NB_VISITS_CONVERTED => 'nb_visits_converted',
+ Piwik_Archive::INDEX_NB_CONVERSIONS => 'nb_conversions',
+ Piwik_Archive::INDEX_REVENUE => 'revenue',
+ Piwik_Archive::INDEX_GOALS => 'goals',
);
+
+ public static $mappingFromIdToNameGoal = array(
+ Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS => 'nb_conversions',
+ Piwik_Archive::INDEX_GOAL_REVENUE => 'revenue',
+ );
+
/*
* string indexed column name => Integer indexed column name
*/
public static $mappingFromNameToId = array(
- 'nb_uniq_visitors' => Piwik_Archive::INDEX_NB_UNIQ_VISITORS,
- 'nb_visits' => Piwik_Archive::INDEX_NB_VISITS,
- 'nb_actions' => Piwik_Archive::INDEX_NB_ACTIONS,
- 'max_actions' => Piwik_Archive::INDEX_MAX_ACTIONS,
- 'sum_visit_length' => Piwik_Archive::INDEX_SUM_VISIT_LENGTH,
- 'bounce_count' => Piwik_Archive::INDEX_BOUNCE_COUNT,
- );
-
- /**
- * Website Piwik_Site
- *
- * @var Piwik_Site
- */
- protected $site = null;
-
- /**
- * Stores the already built archives.
- * Act as a big caching array
- *
- * @var array of Piwik_Archive
- */
- static protected $alreadyBuilt = array();
-
- /**
- * Builds an Archive object or returns the same archive if previously built.
- *
- * @param string|int idSite integer, or comma separated list of integer
- * @param string|Piwik_Date $date 'YYYY-MM-DD' or magic keywords 'today' @see Piwik_Date::factory()
- * @param string $period 'week' 'day' etc.
- *
- * @return Piwik_Archive
- */
- static public function build($idSite, $period, $strDate )
- {
- if($idSite === 'all')
- {
- $sites = Piwik_SitesManager_API::getSitesIdWithAtLeastViewAccess();
- }
- else
- {
- $sites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
+ 'nb_uniq_visitors' => Piwik_Archive::INDEX_NB_UNIQ_VISITORS,
+ 'nb_visits' => Piwik_Archive::INDEX_NB_VISITS,
+ 'nb_actions' => Piwik_Archive::INDEX_NB_ACTIONS,
+ 'max_actions' => Piwik_Archive::INDEX_MAX_ACTIONS,
+ 'sum_visit_length' => Piwik_Archive::INDEX_SUM_VISIT_LENGTH,
+ 'bounce_count' => Piwik_Archive::INDEX_BOUNCE_COUNT,
+ 'nb_visits_converted' => Piwik_Archive::INDEX_NB_VISITS_CONVERTED,
+ 'nb_conversions' => Piwik_Archive::INDEX_NB_CONVERSIONS,
+ 'revenue' => Piwik_Archive::INDEX_REVENUE,
+ 'goals' => Piwik_Archive::INDEX_GOALS,
+ );
+
+ /**
+ * Website Piwik_Site
+ *
+ * @var Piwik_Site
+ */
+ protected $site = null;
+
+ /**
+ * Stores the already built archives.
+ * Act as a big caching array
+ *
+ * @var array of Piwik_Archive
+ */
+ static protected $alreadyBuilt = array();
+
+ /**
+ * Builds an Archive object or returns the same archive if previously built.
+ *
+ * @param string|int idSite integer, or comma separated list of integer
+ * @param string|Piwik_Date $date 'YYYY-MM-DD' or magic keywords 'today' @see Piwik_Date::factory()
+ * @param string $period 'week' 'day' etc.
+ *
+ * @return Piwik_Archive
+ */
+ static public function build($idSite, $period, $strDate )
+ {
+ if($idSite === 'all')
+ {
+ $sites = Piwik_SitesManager_API::getSitesIdWithAtLeastViewAccess();
}
-
- // idSite=1,3 or idSite=all
+ else
+ {
+ $sites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
+ }
+
+ // idSite=1,3 or idSite=all
if( count($sites) > 1
- || $idSite === 'all' )
- {
- require_once 'Archive/Array/IndexedBySite.php';
- $archive = new Piwik_Archive_Array_IndexedBySite($sites, $period, $strDate);
- }
- // if a period date string is detected: either 'last30', 'previous10' or 'YYYY-MM-DD,YYYY-MM-DD'
- elseif(is_string($strDate)
- && (
- ereg('^(last|previous){1}([0-9]*)$', $strDate, $regs)
- || ereg('^([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}),([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})$', $strDate, $regs)
- )
- )
- {
- $oSite = new Piwik_Site($idSite);
- require_once 'Archive/Array/IndexedByDate.php';
- $archive = new Piwik_Archive_Array_IndexedByDate($oSite, $period, $strDate);
- }
- // case we request a single archive
- else
- {
- if(is_string($strDate))
- {
- $oDate = Piwik_Date::factory($strDate);
- }
- else
- {
- $oDate = $strDate;
- }
- $date = $oDate->toString();
-
+ || $idSite === 'all' )
+ {
+ require_once 'Archive/Array/IndexedBySite.php';
+ $archive = new Piwik_Archive_Array_IndexedBySite($sites, $period, $strDate);
+ }
+ // if a period date string is detected: either 'last30', 'previous10' or 'YYYY-MM-DD,YYYY-MM-DD'
+ elseif(is_string($strDate)
+ && (
+ ereg('^(last|previous){1}([0-9]*)$', $strDate, $regs)
+ || ereg('^([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}),([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})$', $strDate, $regs)
+ )
+ )
+ {
+ $oSite = new Piwik_Site($idSite);
+ require_once 'Archive/Array/IndexedByDate.php';
+ $archive = new Piwik_Archive_Array_IndexedByDate($oSite, $period, $strDate);
+ }
+ // case we request a single archive
+ else
+ {
+ if(is_string($strDate))
+ {
+ $oDate = Piwik_Date::factory($strDate);
+ }
+ else
+ {
+ $oDate = $strDate;
+ }
+ $date = $oDate->toString();
+
if(isset(self::$alreadyBuilt[$idSite][$date][$period]))
{
- return self::$alreadyBuilt[$idSite][$date][$period];
- }
-
- $oPeriod = Piwik_Period::factory($period, $oDate);
-
- $archive = new Piwik_Archive_Single();
- $archive->setPeriod($oPeriod);
+ return self::$alreadyBuilt[$idSite][$date][$period];
+ }
+
+ $oPeriod = Piwik_Period::factory($period, $oDate);
+
+ $archive = new Piwik_Archive_Single();
+ $archive->setPeriod($oPeriod);
$archive->setSite(new Piwik_Site($idSite));
- $archiveJustProcessed = $archive->prepareArchive();
+ $archiveJustProcessed = $archive->prepareArchive();
//we don't cache the archives just processed, the datatable were freed from memory
if(!$archiveJustProcessed)
- {
+ {
self::$alreadyBuilt[$idSite][$date][$period] = $archive;
- }
- }
-
- return $archive;
- }
-
- abstract public function prepareArchive();
-
- /**
- * Returns the value of the element $name from the current archive
- * The value to be returned is a numeric value and is stored in the archive_numeric_* tables
- *
- * @param string $name For example Referers_distinctKeywords
- * @return float|int|false False if no value with the given name
- */
- abstract public function getNumeric( $name );
-
- /**
- * Returns the value of the element $name from the current archive
- *
- * The value to be returned is a blob value and is stored in the archive_numeric_* tables
- *
- * It can return anything from strings, to serialized PHP arrays or PHP objects, etc.
- *
- * @param string $name For example Referers_distinctKeywords
- * @return mixed False if no value with the given name
- */
- abstract public function getBlob( $name );
+ }
+ }
+
+ return $archive;
+ }
+
+ abstract public function prepareArchive();
+
+ /**
+ * Returns the value of the element $name from the current archive
+ * The value to be returned is a numeric value and is stored in the archive_numeric_* tables
+ *
+ * @param string $name For example Referers_distinctKeywords
+ * @return float|int|false False if no value with the given name
+ */
+ abstract public function getNumeric( $name );
/**
+ * Returns the value of the element $name from the current archive
*
+ * The value to be returned is a blob value and is stored in the archive_numeric_* tables
+ *
+ * It can return anything from strings, to serialized PHP arrays or PHP objects, etc.
+ *
+ * @param string $name For example Referers_distinctKeywords
+ * @return mixed False if no value with the given name
+ */
+ abstract public function getBlob( $name );
+
+ /**
+ *
+ * @return Piwik_DataTable
+ */
+ abstract public function getDataTableFromNumeric( $fields );
+
+ /**
+ * This method will build a dataTable from the blob value $name in the current archive.
+ *
+ * For example $name = 'Referers_searchEngineByKeyword' will return a Piwik_DataTable containing all the keywords
+ * If a idSubTable is given, the method will return the subTable of $name
+ *
+ * @param string $name
+ * @param int $idSubTable or null if requesting the parent table
+ * @return Piwik_DataTable
+ * @throws exception If the value cannot be found
+ */
+ abstract public function getDataTable( $name, $idSubTable = null );
+
+ /**
+ * Same as getDataTable() except that it will also load in memory
+ * all the subtables for the DataTable $name.
+ * You can then access the subtables by using the Piwik_DataTable_Manager getTable()
+ *
+ * @param string $name
+ * @param int $idSubTable or null if requesting the parent table
* @return Piwik_DataTable
- */
- abstract public function getDataTableFromNumeric( $fields );
-
- /**
- * This method will build a dataTable from the blob value $name in the current archive.
- *
- * For example $name = 'Referers_searchEngineByKeyword' will return a Piwik_DataTable containing all the keywords
- * If a idSubTable is given, the method will return the subTable of $name
- *
- * @param string $name
- * @param int $idSubTable or null if requesting the parent table
- * @return Piwik_DataTable
- * @throws exception If the value cannot be found
- */
- abstract public function getDataTable( $name, $idSubTable = null );
-
- /**
- * Same as getDataTable() except that it will also load in memory
- * all the subtables for the DataTable $name.
- * You can then access the subtables by using the Piwik_DataTable_Manager getTable()
- *
- * @param string $name
- * @param int $idSubTable or null if requesting the parent table
- * @return Piwik_DataTable
- */
- abstract public function getDataTableExpanded($name, $idSubTable = null);
-
- /**
- * Sets the site
- *
- * @param Piwik_Site $site
- */
- public function setSite( Piwik_Site $site )
- {
- $this->site = $site;
- }
-
- /**
- * Gets the site
- *
- * @param Piwik_Site $site
- */
- public function getSite()
- {
- return $this->site;
- }
-
- /**
- * Returns the Id site associated with this archive
- *
- * @return int
- */
- public function getIdSite()
- {
- return $this->site->getId();
- }
-
-}
-
-
-
-
-
+ */
+ abstract public function getDataTableExpanded($name, $idSubTable = null);
+
+ /**
+ * Sets the site
+ *
+ * @param Piwik_Site $site
+ */
+ public function setSite( Piwik_Site $site )
+ {
+ $this->site = $site;
+ }
+
+ /**
+ * Gets the site
+ *
+ * @param Piwik_Site $site
+ */
+ public function getSite()
+ {
+ return $this->site;
+ }
+
+ /**
+ * Returns the Id site associated with this archive
+ *
+ * @return int
+ */
+ public function getIdSite()
+ {
+ return $this->site->getId();
+ }
+
+}
+
+
+
+
+
diff --git a/core/Archive/Single.php b/core/Archive/Single.php
index faf53de1c2..4035e2804b 100644
--- a/core/Archive/Single.php
+++ b/core/Archive/Single.php
@@ -372,6 +372,7 @@ class Piwik_Archive_Single extends Piwik_Archive
* 'nb_actions',
* 'sum_visit_length',
* 'bounce_count',
+ * 'nb_visits_converted'
* );
*
* @param string|array $fields Name or array of names of Archive fields
@@ -454,4 +455,4 @@ class Piwik_Archive_Single extends Piwik_Archive
return $dataTableToLoad;
}
}
-?> \ No newline at end of file
+?>
diff --git a/core/ArchiveProcessing.php b/core/ArchiveProcessing.php
index 6a1ef954bb..9a99636841 100644
--- a/core/ArchiveProcessing.php
+++ b/core/ArchiveProcessing.php
@@ -334,6 +334,7 @@ abstract class Piwik_ArchiveProcessing
$this->logTable = Piwik::prefixTable('log_visit');
$this->logVisitActionTable = Piwik::prefixTable('log_link_visit_action');
$this->logActionTable = Piwik::prefixTable('log_action');
+ $this->logConversionTable = Piwik::prefixTable('log_conversion');
}
/**
@@ -430,6 +431,28 @@ abstract class Piwik_ArchiveProcessing
return $this->timestampDateStart;
}
+
+ // exposing the number of visits publicly (number used to compute conversions rates)
+ protected $nb_visits = null;
+ protected $nb_visits_converted = null;
+
+ protected function setNumberOfVisits($nb_visits)
+ {
+ $this->nb_visits = $nb_visits;
+ }
+ public function getNumberOfVisits()
+ {
+ return $this->nb_visits;
+ }
+ protected function setNumberOfVisitsConverted($nb_visits_converted)
+ {
+ $this->nb_visits_converted = $nb_visits_converted;
+ }
+ public function getNumberOfVisitsConverted()
+ {
+ return $this->nb_visits_converted;
+ }
+
/**
* Returns the idArchive we will use for the current archive
*
@@ -499,7 +522,7 @@ abstract class Piwik_ArchiveProcessing
);
$timeStampWhere = " AND UNIX_TIMESTAMP(ts_archived) >= ? ";
$bindSQL[] = $this->maxTimestampArchive;
-
+
$sqlQuery = " SELECT idarchive, value, name, UNIX_TIMESTAMP(date1) as timestamp
FROM ".$this->tableArchiveNumeric->getTableName()."
WHERE idsite = ?
@@ -510,7 +533,6 @@ abstract class Piwik_ArchiveProcessing
OR name = 'nb_visits')
$timeStampWhere
ORDER BY ts_archived DESC";
-
$results = Zend_Registry::get('db')->fetchAll($sqlQuery, $bindSQL );
if(empty($results))
{
diff --git a/core/ArchiveProcessing/Day.php b/core/ArchiveProcessing/Day.php
index f3a4f5d6c7..300234f3ce 100644
--- a/core/ArchiveProcessing/Day.php
+++ b/core/ArchiveProcessing/Day.php
@@ -11,8 +11,9 @@
/**
- * Handles the archiving process for a day.
- * The class provides generic methods to manipulate data from the DB, easily create Piwik_DataTable objects.
+ * Handles the archiving process for a day.
+ * The class provides generic helper methods to manipulate data from the DB,
+ * easily create Piwik_DataTable objects from running SELECT ... GROUP BY on the log_visit table.
*
* All the logic of the archiving is done inside the plugins listening to the event 'ArchiveProcessing_Day.compute'
*
@@ -51,7 +52,8 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
sum(visit_total_actions) as nb_actions,
max(visit_total_actions) as max_actions,
sum(visit_total_time) as sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted
FROM ".$this->logTable."
WHERE visit_server_date = ?
AND idsite = ?
@@ -70,7 +72,8 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
{
$record = new Piwik_ArchiveProcessing_Record_Numeric($name, $value);
}
-
+ $this->setNumberOfVisits($row['nb_visits']);
+ $this->setNumberOfVisitsConverted($row['nb_visits_converted']);
Piwik_PostEvent('ArchiveProcessing_Day.compute', $this);
}
@@ -138,8 +141,26 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
return $table;
}
+ public function getDataTableFromArray( $array )
+ {
+ $table = new Piwik_DataTable;
+ $table->addRowsFromArrayWithIndexLabel($array);
+ return $table;
+ }
+
/**
- * Helper function that returns common statistics for a given database field distinct values.
+ * Output:
+ * array(
+ * LABEL => array(
+ * Piwik_Archive::INDEX_NB_UNIQ_VISITORS => 0,
+ * Piwik_Archive::INDEX_NB_VISITS => 0
+ * ),
+ * LABEL2 => array(
+ * [...]
+ * )
+ * )
+ *
+ * Helper function that returns an array with common statistics for a given database field distinct values.
*
* The statistics returned are:
* - number of unique visitors
@@ -150,18 +171,18 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
* - count of bouncing visits (visits with one page view)
*
* For example if $label = 'config_os' it will return the statistics for every distinct Operating systems
- * The returned DataTable will have a row per distinct operating systems,
- * and a column per stat (nb of visits, max actions, etc)
+ * The returned array will have a row per distinct operating systems,
+ * and a column per stat (nb of visits, max actions, etc)
*
- * label nb_uniq_visitors nb_visits nb_actions max_actions sum_visit_length bounce_count
- * Linux 27 66 66 1 660 66
- * Windows XP 12 39 39 1 390 39
- * Mac OS 15 36 36 1 360 36
+ * 'label' Piwik_Archive::INDEX_NB_UNIQ_VISITORS Piwik_Archive::INDEX_NB_VISITS etc.
+ * Linux 27 66 ...
+ * Windows XP 12 ...
+ * Mac OS 15 36 ...
*
* @param string $label Table log_visit field name to be use to compute common stats
- * @return Piwik_DataTable
+ * @return array
*/
- public function getDataTableInterestForLabel( $label )
+ public function getArrayInterestForLabel($label)
{
$query = "SELECT $label as label,
count(distinct visitor_idcookie) as nb_uniq_visitors,
@@ -169,34 +190,21 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
sum(visit_total_actions) as nb_actions,
max(visit_total_actions) as max_actions,
sum(visit_total_time) as sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted
FROM ".$this->logTable."
WHERE visit_server_date = ?
AND idsite = ?
GROUP BY label";
-
$query = $this->db->query($query, array( $this->strDateStart, $this->idsite ) );
$interest = array();
- while($rowBefore = $query->fetch())
+ while($row = $query->fetch())
{
- $row = array(
- Piwik_Archive::INDEX_NB_UNIQ_VISITORS => $rowBefore['nb_uniq_visitors'],
- Piwik_Archive::INDEX_NB_VISITS => $rowBefore['nb_visits'],
- Piwik_Archive::INDEX_NB_ACTIONS => $rowBefore['nb_actions'],
- Piwik_Archive::INDEX_MAX_ACTIONS => $rowBefore['max_actions'],
- Piwik_Archive::INDEX_SUM_VISIT_LENGTH => $rowBefore['sum_visit_length'],
- Piwik_Archive::INDEX_BOUNCE_COUNT => $rowBefore['bounce_count'],
- 'label' => $rowBefore['label']
- );
-
if(!isset($interest[$row['label']])) $interest[$row['label']]= $this->getNewInterestRow();
$this->updateInterestStats( $row, $interest[$row['label']]);
}
-
- $table = new Piwik_DataTable;
- $table->addRowsFromArrayWithIndexLabel($interest);
- return $table;
+ return $interest;
}
/**
@@ -259,17 +267,19 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
/**
* Helper function that returns the multiple serialized DataTable of the given PHP array.
* The DataTable here associates a subtable to every row of the level 0 array.
- * This is used for example for search engines. Every search engine (level 0) has a subtable containing the
- * keywords.
+ * This is used for example for search engines.
+ * Every search engine (level 0) has a subtable containing the keywords.
*
* The $arrayLevel0 must have the format
* Example: array (
+ * // Yahoo.com => array( kwd1 => stats, kwd2 => stats )
* LABEL => array(col1 => X, col2 => Y),
* LABEL2 => array(col1 => X, col2 => Y),
* )
*
* The $subArrayLevel1ByKey must have the format
* Example: array(
+ * // Yahoo.com => array( stats )
* LABEL => #Piwik_DataTable_ForLABEL,
* LABEL2 => #Piwik_DataTable_ForLABEL2,
* )
@@ -279,10 +289,9 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
* @param array of Piwik_DataTable $subArrayLevel1ByKey
* @return array Array with N elements: the strings of the datatable serialized
*/
- public function getDataTablesSerialized( $arrayLevel0, $subArrayLevel1ByKey, $maximumRowsInDataTableLevelZero = null, $maximumRowsInSubDataTable = null)
+ public function getDataTableWithSubtablesFromArraysIndexedByLabel( $arrayLevel0, $subArrayLevel1ByKey )
{
$tablesByLabel = array();
-
foreach($arrayLevel0 as $label => $aAllRowsForThisLabel)
{
$table = new Piwik_DataTable;
@@ -292,8 +301,7 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
$parentTableLevel0 = new Piwik_DataTable;
$parentTableLevel0->addRowsFromArrayWithIndexLabel($subArrayLevel1ByKey, $tablesByLabel);
- $toReturn = $parentTableLevel0->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- return $toReturn;
+ return $parentTableLevel0;
}
/**
@@ -308,7 +316,8 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
Piwik_Archive::INDEX_NB_ACTIONS => 0,
Piwik_Archive::INDEX_MAX_ACTIONS => 0,
Piwik_Archive::INDEX_SUM_VISIT_LENGTH => 0,
- Piwik_Archive::INDEX_BOUNCE_COUNT => 0
+ Piwik_Archive::INDEX_BOUNCE_COUNT => 0,
+ Piwik_Archive::INDEX_NB_VISITS_CONVERTED=> 0,
);
}
@@ -339,13 +348,124 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
* @param array $oldRowToUpdate
*/
public function updateInterestStats( $newRowToAdd, &$oldRowToUpdate)
- {
- $oldRowToUpdate[Piwik_Archive::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd[Piwik_Archive::INDEX_NB_UNIQ_VISITORS];
- $oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS] += $newRowToAdd[Piwik_Archive::INDEX_NB_VISITS];
- $oldRowToUpdate[Piwik_Archive::INDEX_NB_ACTIONS] += $newRowToAdd[Piwik_Archive::INDEX_NB_ACTIONS];
- $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS] = (float)max($newRowToAdd[Piwik_Archive::INDEX_MAX_ACTIONS], $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS]);
- $oldRowToUpdate[Piwik_Archive::INDEX_SUM_VISIT_LENGTH] += $newRowToAdd[Piwik_Archive::INDEX_SUM_VISIT_LENGTH];
- $oldRowToUpdate[Piwik_Archive::INDEX_BOUNCE_COUNT] += $newRowToAdd[Piwik_Archive::INDEX_BOUNCE_COUNT];
+ {
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd['nb_uniq_visitors'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS] += $newRowToAdd['nb_visits'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_ACTIONS] += $newRowToAdd['nb_actions'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS] = (float)max($newRowToAdd['max_actions'], $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS]);
+ $oldRowToUpdate[Piwik_Archive::INDEX_SUM_VISIT_LENGTH] += $newRowToAdd['sum_visit_length'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_BOUNCE_COUNT] += $newRowToAdd['bounce_count'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS_CONVERTED] += $newRowToAdd['nb_visits_converted'];
+ }
+
+ //TODO comment
+ public function queryConversionsBySegment($segments = '')
+ {
+ if(!empty($segments))
+ {
+ $segments = ", ". $segments;
+ }
+ $query = "SELECT idgoal,
+ count(*) as nb_conversions,
+ sum(revenue) as revenue
+ $segments
+ FROM ".$this->logConversionTable."
+ WHERE visit_server_date = ?
+ AND idsite = ?
+ GROUP BY idgoal $segments";
+ $query = $this->db->query($query, array( $this->strDateStart, $this->idsite ));
+ return $query;
+ }
+
+ public function queryConversionsBySingleSegment($segment)
+ {
+ $query = "SELECT idgoal,
+ count(*) as nb_conversions,
+ sum(revenue) as revenue,
+ $segment as label
+ FROM ".$this->logConversionTable."
+ WHERE visit_server_date = ?
+ AND idsite = ?
+ GROUP BY idgoal, label";
+ $query = $this->db->query($query, array( $this->strDateStart, $this->idsite ));
+ return $query;
+ }
+
+ /**
+ * Input:
+ * array(
+ * LABEL => array( Piwik_Archive::INDEX_NB_VISITS => X,
+ * Piwik_Archive::INDEX_GOALS => array(
+ * idgoal1 => array( [...] ),
+ * idgoal2 => array( [...] ),
+ * ),
+ * [...] ),
+ * LABEL2 => array( Piwik_Archive::INDEX_NB_VISITS => Y, [...] )
+ * );
+ *
+ * Output:
+ * array(
+ * LABEL => array( Piwik_Archive::INDEX_NB_VISITS => X,
+ *
+ * Piwik_Archive::INDEX_GOALS => array(
+ * idgoal1 => array( [...] ),
+ * idgoal2 => array( [...] ),
+ * ),
+ * [...] ),
+ * LABEL2 => array( Piwik_Archive::INDEX_NB_VISITS => Y, [...] )
+ * );
+ * )
+ * @param array by reference, will be modified
+ * @return void (array by reference is modified)
+ */
+ function enrichConversionsByLabelArray(&$interestByLabel)
+ {
+ foreach($interestByLabel as $label => &$values)
+ {
+ if(isset($values[Piwik_Archive::INDEX_GOALS]))
+ {
+ $revenue = $conversions = 0;
+ foreach($values[Piwik_Archive::INDEX_GOALS] as $idgoal => $goalValues)
+ {
+ $revenue += $goalValues[Piwik_Archive::INDEX_GOAL_REVENUE];
+ $conversions += $goalValues[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS];
+ }
+ $values[Piwik_Archive::INDEX_NB_CONVERSIONS] = $conversions;
+ $values[Piwik_Archive::INDEX_REVENUE] = $revenue;
+ }
+ }
+ }
+
+ /**
+ * @param array $interestByLabelAndSubLabel
+ * @return void (array by reference is modified)
+ */
+ function enrichConversionsByLabelArrayHasTwoLevels(&$interestByLabelAndSubLabel)
+ {
+ foreach($interestByLabelAndSubLabel as $mainLabel => &$interestBySubLabel)
+ {
+ $this->enrichConversionsByLabelArray($interestBySubLabel);
+ }
+ }
+
+ function updateGoalStats($newRowToAdd, &$oldRowToUpdate)
+ {
+ $oldRowToUpdate[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS] += $newRowToAdd['nb_conversions'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_GOAL_REVENUE] += $newRowToAdd['revenue'];
+ }
+
+ function getNewGoalRow()
+ {
+ return array( Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS => 0,
+ Piwik_Archive::INDEX_GOAL_REVENUE => 0,
+ );
+ }
+
+ function getGoalRowFromQueryRow($queryRow)
+ {
+ return array( Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS => $queryRow['nb_conversions'],
+ Piwik_Archive::INDEX_GOAL_REVENUE => $queryRow['revenue'],
+ );
}
}
diff --git a/core/ArchiveProcessing/Period.php b/core/ArchiveProcessing/Period.php
index 7e834bec62..a4deaa3faf 100644
--- a/core/ArchiveProcessing/Period.php
+++ b/core/ArchiveProcessing/Period.php
@@ -119,7 +119,7 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
/**
- * This powerful method will compute the sum of DataTables over the period for the given fields $aRecordName.
+ * This method will compute the sum of DataTables over the period for the given fields $aRecordName.
* The resulting DataTable will be then added to queue of data to be recorded in the database.
* It will usually be called in a plugin that listens to the hook 'ArchiveProcessing_Period.compute'
*
@@ -223,20 +223,24 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
{
$this->archiveNumericValuesMax( 'max_actions' );
$toSum = array(
- 'nb_uniq_visitors',
+ 'nb_uniq_visitors', //TODO fix
'nb_visits',
'nb_actions',
'sum_visit_length',
'bounce_count',
+ 'nb_visits_converted',
);
$record = $this->archiveNumericValuesSum($toSum);
- $this->isThereSomeVisits = ($record['nb_visits']->value != 0);
+ $nbVisits = $record['nb_visits']->value;
+ $nbVisitsConverted = $record['nb_visits_converted']->value;
+ $this->isThereSomeVisits = ( $nbVisits!= 0);
if($this->isThereSomeVisits === false)
{
return;
}
-
+ $this->setNumberOfVisits($nbVisits);
+ $this->setNumberOfVisitsConverted($nbVisitsConverted);
Piwik_PostEvent('ArchiveProcessing_Period.compute', $this);
}
@@ -250,21 +254,25 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
{
parent::postCompute();
- // we delete records that are now out of date
- // in the case of a period we delete archives that were archived before the end of the period
- // and only if they are at least 1 day old (so we don't delete archives computed today that may be stil valid)
- $blobTable = $this->tableArchiveBlob->getTableName();
- $numericTable = $this->tableArchiveNumeric->getTableName();
-
- $query = " DELETE
- FROM %s
- WHERE period > ?
- AND DATE(ts_archived) <= date2
- AND date(ts_archived) < date_sub(CURRENT_DATE(), INTERVAL 1 DAY)
- ";
-
- Zend_Registry::get('db')->query(sprintf($query, $blobTable), Piwik::$idPeriods['day']);
- Zend_Registry::get('db')->query(sprintf($query, $numericTable), Piwik::$idPeriods['day']);
+ //TODO should be done in a different asynchronous job
+ if(rand(0, 15) == 5)
+ {
+ // we delete records that are now out of date
+ // in the case of a period we delete archives that were archived before the end of the period
+ // and only if they are at least 1 day old (so we don't delete archives computed today that may be stil valid)
+ $blobTable = $this->tableArchiveBlob->getTableName();
+ $numericTable = $this->tableArchiveNumeric->getTableName();
+
+ $query = " DELETE
+ FROM %s
+ WHERE period > ?
+ AND DATE(ts_archived) <= date2
+ AND date(ts_archived) < date_sub(CURRENT_DATE(), INTERVAL 1 DAY)
+ ";
+
+ Zend_Registry::get('db')->query(sprintf($query, $blobTable), Piwik::$idPeriods['day']);
+ Zend_Registry::get('db')->query(sprintf($query, $numericTable), Piwik::$idPeriods['day']);
+ }
}
}
diff --git a/core/ArchiveProcessing/Record/BlobArray.php b/core/ArchiveProcessing/Record/BlobArray.php
index 4e3165489e..de187ac62d 100644
--- a/core/ArchiveProcessing/Record/BlobArray.php
+++ b/core/ArchiveProcessing/Record/BlobArray.php
@@ -32,7 +32,6 @@
*/
class Piwik_ArchiveProcessing_Record_BlobArray extends Piwik_ArchiveProcessing_Record
{
-
function __construct( $name, $aValue)
{
foreach($aValue as $id => $value)
@@ -49,13 +48,14 @@ class Piwik_ArchiveProcessing_Record_BlobArray extends Piwik_ArchiveProcessing_R
$newName = $name . '_' . $id;
}
$record = new Piwik_ArchiveProcessing_Record_Blob( $newName, $value );
-
}
}
+
public function __toString()
{
throw new Exception( 'Not valid' );
}
+
public function delete()
{
throw new Exception( 'Not valid' );
diff --git a/core/Common.php b/core/Common.php
index 2cca73ce91..7b43f2e693 100644
--- a/core/Common.php
+++ b/core/Common.php
@@ -124,22 +124,22 @@ class Piwik_Common
if( false !== strpos($value, '='))
{
$exploded = explode('=',$value);
- $name = $exploded[0];
-
- // if array without indexes
- if( substr($name,-2,2) == '[]' )
- {
- $name = substr($name, 0, -2);
- if( isset($nameToValue[$name]) == false || is_array($nameToValue[$name]) == false )
- {
- $nameToValue[$name] = array();
- }
- array_push($nameToValue[$name],$exploded[1]);
- }
- else
- {
- $nameToValue[$name] = $exploded[1];
- }
+ $name = $exploded[0];
+
+ // if array without indexes
+ if( substr($name,-2,2) == '[]' )
+ {
+ $name = substr($name, 0, -2);
+ if( isset($nameToValue[$name]) == false || is_array($nameToValue[$name]) == false )
+ {
+ $nameToValue[$name] = array();
+ }
+ array_push($nameToValue[$name],$exploded[1]);
+ }
+ else
+ {
+ $nameToValue[$name] = $exploded[1];
+ }
}
}
return $nameToValue;
diff --git a/core/Controller.php b/core/Controller.php
index 95356c27bf..e544796d58 100644
--- a/core/Controller.php
+++ b/core/Controller.php
@@ -9,6 +9,7 @@
* @package Piwik
*/
+require_once "ViewDataTable.php";
/**
* Parent class of all plugins Controllers (located in /plugins/PluginName/Controller.php
* It defines some helper functions controllers can use.
@@ -78,6 +79,15 @@ abstract class Piwik_Controller
*/
protected function renderView( Piwik_ViewDataTable $view, $fetch)
{
+ Piwik_PostEvent( 'Controller.renderView',
+ $this,
+ array( 'view' => $view,
+ 'controllerName' => $view->getCurrentControllerName(),
+ 'controllerAction' => $view->getCurrentControllerAction(),
+ 'apiMethodToRequestDataTable' => $view->getApiMethodToRequestDataTable(),
+ 'controllerActionCalledWhenRequestSubTable' => $view->getControllerActionCalledWhenRequestSubTable(),
+ )
+ );
$view->main();
$rendered = $view->getView()->render();
if($fetch)
diff --git a/core/DataTable.php b/core/DataTable.php
index 2d94c53ee4..3f52385512 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -170,6 +170,13 @@ class Piwik_DataTable
protected $indexNotUpToDate = false;
/**
+ * Column name of last time the table was sorted
+ *
+ * @var string
+ */
+ protected $tableSortedBy = false;
+
+ /**
* List of Piwik_DataTable_Filter queued to this table
*
* @var array
@@ -218,10 +225,12 @@ class Piwik_DataTable
* Sort the dataTable rows using the php callback function
*
* @param string $functionCallback
+ * @param string $columnSortedBy The column name. Used to then ask the datatable what column are you sorted by
*/
- public function sort( $functionCallback )
+ public function sort( $functionCallback, $columnSortedBy )
{
$this->indexNotUpToDate = true;
+ $this->tableSortedBy = $columnSortedBy;
usort( $this->rows, $functionCallback );
if($this->enableRecursiveSort === true)
@@ -232,12 +241,17 @@ class Piwik_DataTable
{
$table = Piwik_DataTable_Manager::getInstance()->getTable($idSubtable);
$table->enableRecursiveSort();
- $table->sort($functionCallback);
+ $table->sort($functionCallback, $columnSortedBy);
}
}
}
}
+ public function getSortedByColumnName()
+ {
+ return $this->tableSortedBy;
+ }
+
/**
* Enables the recursive sort. Means that when using $table->sort()
* it will also sort all subtables using the same callback
diff --git a/core/DataTable/Filter.php b/core/DataTable/Filter.php
index de03b1cfec..46984d5426 100644
--- a/core/DataTable/Filter.php
+++ b/core/DataTable/Filter.php
@@ -59,4 +59,5 @@ require_once "DataTable/Filter/AddSummaryRow.php";
require_once "DataTable/Filter/ReplaceSummaryRowLabel.php";
require_once "DataTable/Filter/ExactMatch.php";
require_once "DataTable/Filter/SafeDecodeLabel.php";
-require_once "DataTable/Filter/AddColumnsWhenShowAllColumns.php";
+require_once "DataTable/Filter/AddColumnsWhenShowAllColumns.php";
+require_once "DataTable/Filter/UpdateColumnsWhenShowAllGoals.php";
diff --git a/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php b/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php
index fd5810512e..7e5427570f 100644
--- a/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php
+++ b/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php
@@ -24,4 +24,5 @@ class Piwik_DataTable_Filter_AddColumnsWhenShowAllColumns extends Piwik_DataTabl
$row->addColumn('bounce_rate', $bounceRate);
}
}
-} \ No newline at end of file
+}
+
diff --git a/core/DataTable/Filter/AddSummaryRow.php b/core/DataTable/Filter/AddSummaryRow.php
index f5763ffa07..a62c5dc2da 100644
--- a/core/DataTable/Filter/AddSummaryRow.php
+++ b/core/DataTable/Filter/AddSummaryRow.php
@@ -60,8 +60,8 @@ class Piwik_DataTable_Filter_AddSummaryRow extends Piwik_DataTable_Filter
$newRow->sumRow($rows[$i]);
}
}
- $newRow->addColumn('label', $this->labelSummaryRow);
+ $newRow->addColumn('label', $this->labelSummaryRow);
$filter = new Piwik_DataTable_Filter_Limit($this->table, 0, $this->startRowToSummarize);
$this->table->addSummaryRow($newRow);
}
diff --git a/core/DataTable/Filter/ExactMatch.php b/core/DataTable/Filter/ExactMatch.php
index 1027fc62a6..3f68658d61 100644
--- a/core/DataTable/Filter/ExactMatch.php
+++ b/core/DataTable/Filter/ExactMatch.php
@@ -1,52 +1,52 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id$
- *
- * @package Piwik_DataTable
- */
-
-/**
- * Delete all rows for which the given $columnToFilter do not equal $patternToSearch
- * This filter can be used on both integer and string columns.
- * You can pass an array of integers in $patternToSearch parameter.
- *
- * @package Piwik_DataTable
- * @subpackage Piwik_DataTable_Filter
- */
-class Piwik_DataTable_Filter_ExactMatch extends Piwik_DataTable_Filter
-{
- private $columnToFilter;
- private $patternToSearch;
-
- public function __construct( $table, $columnToFilter, $patternToSearch )
- {
- parent::__construct($table);
- $this->patternToSearch = $patternToSearch;
- $this->columnToFilter = $columnToFilter;
- $this->filter();
- }
-
- protected function filter()
- {
- foreach($this->table->getRows() as $key => $row)
- {
- if( is_array($this->patternToSearch) )
- {
- if( in_array($row->getColumn($this->columnToFilter), $this->patternToSearch) == false )
- {
- $this->table->deleteRow($key);
- }
- }
- else if( $row->getColumn($this->columnToFilter) != $this->patternToSearch )
- {
- $k = $row->getColumn($this->columnToFilter);
- $this->table->deleteRow($key);
- }
- }
- }
-}
-
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_DataTable
+ */
+
+/**
+ * Delete all rows for which the given $columnToFilter do not equal $patternToSearch
+ * This filter can be used on both integer and string columns.
+ * You can pass an array of integers in $patternToSearch parameter.
+ *
+ * @package Piwik_DataTable
+ * @subpackage Piwik_DataTable_Filter
+ */
+class Piwik_DataTable_Filter_ExactMatch extends Piwik_DataTable_Filter
+{
+ private $columnToFilter;
+ private $patternToSearch;
+
+ public function __construct( $table, $columnToFilter, $patternToSearch )
+ {
+ parent::__construct($table);
+ $this->patternToSearch = $patternToSearch;
+ $this->columnToFilter = $columnToFilter;
+ $this->filter();
+ }
+
+ protected function filter()
+ {
+ foreach($this->table->getRows() as $key => $row)
+ {
+ if( is_array($this->patternToSearch) )
+ {
+ if( in_array($row->getColumn($this->columnToFilter), $this->patternToSearch) == false )
+ {
+ $this->table->deleteRow($key);
+ }
+ }
+ else if( $row->getColumn($this->columnToFilter) != $this->patternToSearch )
+ {
+ $k = $row->getColumn($this->columnToFilter);
+ $this->table->deleteRow($key);
+ }
+ }
+ }
+}
+
diff --git a/core/DataTable/Filter/ExcludeLowPopulation.php b/core/DataTable/Filter/ExcludeLowPopulation.php
index cb038d6d78..94acd0baea 100644
--- a/core/DataTable/Filter/ExcludeLowPopulation.php
+++ b/core/DataTable/Filter/ExcludeLowPopulation.php
@@ -24,21 +24,29 @@ class Piwik_DataTable_Filter_ExcludeLowPopulation extends Piwik_DataTable_Filter
static public $minimumValue;
public function __construct( $table, $columnToFilter, $minimumValue )
{
+ parent::__construct($table);
$this->columnToFilter = $columnToFilter;
+
+ if($minimumValue == 0)
+ {
+ $minimumPercentageThreshold = 0.02;
+ $allValues = $this->table->getColumn($this->columnToFilter);
+ $sumValues = array_sum($allValues);
+ $minimumValue = $sumValues * $minimumPercentageThreshold;
+ }
self::$minimumValue = $minimumValue;
- parent::__construct($table);
- $this->filter();
+ if(self::$minimumValue > 1)
+ {
+ $this->filter();
+ }
}
function filter()
{
- $function = array("Piwik_DataTable_Filter_ExcludeLowPopulation",
- "excludeLowPopulation");
-
$filter = new Piwik_DataTable_Filter_ColumnCallbackDeleteRow(
$this->table,
$this->columnToFilter,
- $function
+ array("Piwik_DataTable_Filter_ExcludeLowPopulation", "excludeLowPopulation")
);
}
diff --git a/core/DataTable/Filter/ReplaceColumnNames.php b/core/DataTable/Filter/ReplaceColumnNames.php
index f1bc174c4a..8d25c960ac 100644
--- a/core/DataTable/Filter/ReplaceColumnNames.php
+++ b/core/DataTable/Filter/ReplaceColumnNames.php
@@ -55,7 +55,9 @@ class Piwik_DataTable_Filter_ReplaceColumnNames extends Piwik_DataTable_Filter
{
foreach($table->getRows() as $key => $row)
{
- $this->renameColumns($row);
+ $oldColumns = $row->getColumns();
+ $newColumns = $this->getRenamedColumns($oldColumns);
+ $row->setColumns( $newColumns );
try {
$subTable = Piwik_DataTable_Manager::getInstance()->getTable( $row->getIdSubDataTable() );
$this->filterTable($subTable);
@@ -65,18 +67,31 @@ class Piwik_DataTable_Filter_ReplaceColumnNames extends Piwik_DataTable_Filter
}
}
- protected function renameColumns($row)
+ protected function getRenamedColumns($columns)
{
- $columns = $row->getColumns();
- foreach($this->mappingToApply as $oldName => $newName)
+ $newColumns = array();
+ foreach($columns as $columnName => $columnValue)
{
- if(isset($columns[$oldName]))
+ if(isset(Piwik_Archive::$mappingFromIdToName[$columnName]))
{
- $columns[$newName] = $columns[$oldName];
- unset($columns[$oldName]);
+ $columnName = Piwik_Archive::$mappingFromIdToName[$columnName];
+ if($columnName == 'goals')
+ {
+ $newSubColumns = array();
+ foreach($columnValue as $idGoal => $goalValues)
+ {
+ foreach($goalValues as $id => $goalValue)
+ {
+ $subColumnName = Piwik_Archive::$mappingFromIdToNameGoal[$id];
+ $newSubColumns['idgoal='.$idGoal][$subColumnName] = $goalValue;
+ }
+ }
+ $columnValue = $newSubColumns;
+ }
}
+ $newColumns[$columnName] = $columnValue;
}
- $row->setColumns($columns);
+ return $newColumns;
}
}
diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php
index 805a8ed28e..148bb5b6e1 100644
--- a/core/DataTable/Filter/Sort.php
+++ b/core/DataTable/Filter/Sort.php
@@ -85,6 +85,40 @@ class Piwik_DataTable_Filter_Sort extends Piwik_DataTable_Filter
);
}
+ /**
+ * @param Piwik_DataTable_Row
+ */
+ protected function selectColumnToSort($row)
+ {
+ $value = $row->getColumn($this->columnToSort);
+ if($value !== false)
+ {
+ return $this->columnToSort;
+ }
+
+ // sorting by "nb_visits" but the index is Piwik_Archive::INDEX_NB_VISITS in the table
+ if(isset(Piwik_Archive::$mappingFromNameToId[$this->columnToSort]))
+ {
+ $column = Piwik_Archive::$mappingFromNameToId[$this->columnToSort];
+ $value = $row->getColumn($column);
+
+ if($value !== false)
+ {
+ return $column;
+ }
+ }
+
+ // eg. was previously sorted by revenue_per_visit, but this table
+ // doesn't have this column; defaults with nb_visits
+ $column = Piwik_Archive::INDEX_NB_VISITS;
+ $value = $row->getColumn($column);
+ if($value !== false)
+ {
+ return $column;
+ }
+
+ return false;
+ }
protected function filter()
{
if($this->table instanceof Piwik_DataTable_Simple)
@@ -97,26 +131,14 @@ class Piwik_DataTable_Filter_Sort extends Piwik_DataTable_Filter
return;
}
$row = current($rows);
- $value = $row->getColumn($this->columnToSort);
+ $this->columnToSort = $this->selectColumnToSort($row);
- if($value === false)
+ if($this->columnToSort === false)
{
- if(!isset(Piwik_Archive::$mappingFromNameToId[$this->columnToSort]))
- {
- // we don't throw the exception because we sometimes export a DataTable without a column labelled '2'
- // and when the generic filters tries to sort by default using this column 2, this shouldnt raise an exception...
- //throw new Exception("The column to sort by '".$this->columnToSort."' is unknown in the row ". implode(array_keys($row->getColumns()), ','));
- return;
- }
- // case we are sorting by "nb_visits" but the column is still integer indexed
- $this->columnToSort = Piwik_Archive::$mappingFromNameToId[$this->columnToSort];
- $value = $row->getColumn($this->columnToSort);
- if($value === false)
- {
- return;
- }
+ return;
}
+ $value = $row->getColumn($this->columnToSort);
if( Piwik::isNumeric($value))
{
$methodToUse = "sort";
@@ -132,7 +154,7 @@ class Piwik_DataTable_Filter_Sort extends Piwik_DataTable_Filter
$methodToUse = "sortString";
}
}
- $this->table->sort( array($this,$methodToUse) );
+ $this->table->sort( array($this,$methodToUse), $this->columnToSort );
}
}
diff --git a/core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php b/core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php
new file mode 100644
index 0000000000..61ce48a8cc
--- /dev/null
+++ b/core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_DataTable
+ */
+
+/**
+ * @package Piwik_DataTable
+ * @subpackage Piwik_DataTable_Filter
+ */
+class Piwik_DataTable_Filter_UpdateColumnsWhenShowAllGoals extends Piwik_DataTable_Filter
+{
+ protected $mappingIdToNameGoal;
+
+ public function __construct( $table, $mappingToApply = null )
+ {
+ parent::__construct($table);
+ $this->mappingIdToNameGoal = Piwik_Archive::$mappingFromIdToNameGoal;
+ $this->filter();
+ }
+
+ protected function filter()
+ {
+ $invalidDivision = 'N/A';
+ $roundingPrecision = 2;
+ $expectedColumns = array();
+ foreach($this->table->getRows() as $key => $row)
+ {
+ $currentColumns = $row->getColumns();
+ $newColumns = array();
+
+ $nbVisits = 0;
+ // visits could be undefined when there is a convertion but no visit
+ if(isset($currentColumns[Piwik_Archive::INDEX_NB_VISITS]))
+ {
+ $nbVisits = $currentColumns[Piwik_Archive::INDEX_NB_VISITS];
+ }
+ $newColumns['nb_visits'] = $nbVisits;
+ $newColumns['label'] = $currentColumns['label'];
+
+ if(isset($currentColumns[Piwik_Archive::INDEX_GOALS]))
+ {
+ $nbVisitsConverted = $revenue = 0;
+ if(isset($currentColumns[Piwik_Archive::INDEX_NB_VISITS_CONVERTED]))
+ {
+ $nbVisitsConverted = $currentColumns[Piwik_Archive::INDEX_NB_VISITS_CONVERTED];
+ $revenue = $currentColumns[Piwik_Archive::INDEX_REVENUE];
+ }
+
+ if($nbVisitsConverted == 0)
+ {
+ $conversionRate = $invalidDivision;
+ }
+ else
+ {
+ $conversionRate = round(100 * $nbVisitsConverted / $nbVisits, $roundingPrecision);
+ }
+
+ if($nbVisits == 0)
+ {
+ $revenuePerVisit = $invalidDivision;
+ }
+ else
+ {
+ $revenuePerVisit = round( $revenue / $nbVisits, $roundingPrecision );
+ }
+ foreach($currentColumns[Piwik_Archive::INDEX_GOALS] as $goalId => $columnValue)
+ {
+ $name = 'goal_' . $goalId . '_conversion_rate';
+ if($nbVisits == 0)
+ {
+ $value = $invalidDivision;
+ }
+ else
+ {
+ $value = round(100 * $columnValue[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS] / $nbVisits, $roundingPrecision);
+ }
+ $newColumns[$name] = $value;
+ $expectedColumns[$name] = true;
+
+ $name = 'goal_' . $goalId . '_nb_conversions';
+ $newColumns[$name] = $columnValue[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS];
+ $expectedColumns[$name] = true;
+ }
+ $newColumns['revenue_per_visit'] = $revenuePerVisit;
+ $newColumns['goals_conversion_rate'] = $conversionRate;
+ }
+
+ $row->setColumns($newColumns);
+ }
+ $expectedColumns['revenue_per_visit'] = true;
+ $expectedColumns['goals_conversion_rate'] = true;
+
+ // make sure all goals values are set, 0 by default
+ // if no value then sorting would put at the end
+ $expectedColumns = array_keys($expectedColumns);
+ $rows = $this->table->getRows();
+ foreach($rows as &$row)
+ {
+ foreach($expectedColumns as $name)
+ {
+ if(false === $row->getColumn($name))
+ {
+ $row->addColumn($name, 0);
+ }
+ }
+ }
+ }
+}
+
diff --git a/core/DataTable/Renderer/Csv.php b/core/DataTable/Renderer/Csv.php
index e686ba9023..d311981c51 100644
--- a/core/DataTable/Renderer/Csv.php
+++ b/core/DataTable/Renderer/Csv.php
@@ -132,11 +132,28 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
$columns = $row->getColumns();
foreach($columns as $name => $value)
{
- if(!isset($allColumns[$name]))
+ //goals => array( 'idgoal=1' =>array(..), 'idgoal=2' => array(..))
+ if(is_array($value))
+ {
+ foreach($value as $key => $subValues)
+ {
+ if(is_array($subValues))
+ {
+ foreach($subValues as $subKey => $subValue)
+ {
+ // goals_idgoal=1
+ $columnName = $name . "_" . $key . "_" . $subKey;
+ $allColumns[$columnName] = true;
+ $csvRow[$columnName] = $subValue;
+ }
+ }
+ }
+ }
+ else
{
$allColumns[$name] = true;
+ $csvRow[$name] = $value;
}
- $csvRow[$name] = $value;
}
if($this->exportMetadata)
diff --git a/core/DataTable/Renderer/Php.php b/core/DataTable/Renderer/Php.php
index 5e472d7519..fee43640f1 100644
--- a/core/DataTable/Renderer/Php.php
+++ b/core/DataTable/Renderer/Php.php
@@ -173,7 +173,7 @@ class Piwik_DataTable_Renderer_Php extends Piwik_DataTable_Renderer
'columns' => $row->getColumns(),
'metadata' => $row->getMetadata(),
'idsubdatatable' => $row->getIdSubDataTable(),
- );
+ );
if($this->renderSubTables
&& $row->getIdSubDataTable() !== null)
diff --git a/core/DataTable/Renderer/Rss.php b/core/DataTable/Renderer/Rss.php
index 18574dfcd5..7f7efa1b23 100644
--- a/core/DataTable/Renderer/Rss.php
+++ b/core/DataTable/Renderer/Rss.php
@@ -97,7 +97,7 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
<lastBuildDate>$generationDate</lastBuildDate>";
return $header;
}
-
+
protected function renderDataTable($table)
{
@@ -110,7 +110,7 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
{
$table->deleteColumn('label');
}
-
+
$i = 1;
$tableStructure = array();
@@ -125,6 +125,12 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
{
foreach($row->getColumns() as $column => $value)
{
+ // for example, goals data is array: not supported in export RSS
+ // in the future we shall reuse ViewDataTable for html exports in RSS anyway
+ if(is_array($value))
+ {
+ continue;
+ }
$allColumns[$column] = true;
$tableStructure[$i][$column] = $value;
}
@@ -146,14 +152,14 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
foreach($tableStructure as $row)
{
$html .= "\n\n<tr>";
- foreach($allColumns as $name => $toDisplay)
+ foreach($allColumns as $columnName => $toDisplay)
{
if($toDisplay !== false)
{
$value = "-";
- if(isset($row[$name]))
+ if(isset($row[$columnName]))
{
- $value = urldecode($row[$name]);
+ $value = urldecode($row[$columnName]);
}
$html .= "\n\t<td>$value</td>";
diff --git a/core/DataTable/Renderer/Xml.php b/core/DataTable/Renderer/Xml.php
index 425f506ae3..1b3a77866d 100644
--- a/core/DataTable/Renderer/Xml.php
+++ b/core/DataTable/Renderer/Xml.php
@@ -29,6 +29,7 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
function render()
{
+// var_dump($this->table);exit;
return $this->renderTable($this->table);
}
@@ -41,7 +42,7 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
protected function renderTable($table, $returnOnlyDataTableXml = false, $prefixLines = '')
{
$array = $this->getArrayFromDataTable($table);
-
+// var_dump($array);exit;
if($table instanceof Piwik_DataTable_Array)
{
$out = $this->renderDataTableArray($table, $array, $prefixLines);
@@ -235,9 +236,21 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
protected function renderDataTable( $array, $prefixLine = "" )
{
$out = '';
- foreach($array as $row)
+ foreach($array as $rowId => $row)
{
- $out .= $prefixLine."\t<row>";
+ if(!is_array($row))
+ {
+ $value = $this->formatValue($row);
+ $out .= $prefixLine."\t\t<$rowId>".$value."</$rowId>\n";
+ continue;
+ }
+ $rowAttribute = '';
+ if(($equalFound = strstr($rowId, '=')) !== false)
+ {
+ $rowAttribute = explode('=', $rowId);
+ $rowAttribute = " " . $rowAttribute[0] . "='" . $rowAttribute[1] . "'";
+ }
+ $out .= $prefixLine."\t<row$rowAttribute>";
if(count($row) === 1
&& key($row) === 0)
diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php
index 9c5edfdd33..abc6aea288 100644
--- a/core/DataTable/Row.php
+++ b/core/DataTable/Row.php
@@ -329,39 +329,49 @@ class Piwik_DataTable_Row
*/
public function sumRow( Piwik_DataTable_Row $rowToSum )
{
- foreach($rowToSum->getColumns() as $name => $value)
+ foreach($rowToSum->getColumns() as $columnToSumName => $columnToSumValue)
{
- if($name != 'label')
+ if($columnToSumName != 'label')
{
- if(Piwik::isNumeric($value))
- {
- $current = $this->getColumn($name);
- if($current === false)
- {
- $current = 0;
- }
- $this->setColumn( $name, $current + $value);
- }
- elseif(is_array($value))
+ $thisColumnValue = $this->getColumn($columnToSumName);
+ $newValue = $this->sumRowArray($thisColumnValue, $columnToSumValue);
+ $this->setColumn( $columnToSumName, $newValue);
+ }
+ }
+ }
+
+ protected function sumRowArray( $thisColumnValue, $columnToSumValue )
+ {
+ $newValue = 0;
+ if(Piwik::isNumeric($columnToSumValue))
+ {
+ if($thisColumnValue === false)
+ {
+ $thisColumnValue = 0;
+ }
+ $newValue = $thisColumnValue + $columnToSumValue;
+ }
+ elseif(is_array($columnToSumValue))
+ {
+ $newValue = array();
+ if($thisColumnValue == false)
+ {
+ $newValue = $columnToSumValue;
+ }
+ else
+ {
+ $newValue = $thisColumnValue;
+ foreach($columnToSumValue as $arrayIndex => $arrayValue)
{
- $current = $this->getColumn($name);
- $newValue = array();
- if($current == false)
+ if(!isset($newValue[$arrayIndex]))
{
- $newValue = $value;
+ $newValue[$arrayIndex] = false;
}
- else
- {
- $newValue = $current;
- foreach($value as $arrayIndex => $arrayValue)
- {
- $newValue[$arrayIndex] += $arrayValue;
- }
- }
- $this->setColumn($name, $newValue);
+ $newValue[$arrayIndex] = $this->sumRowArray($newValue[$arrayIndex], $arrayValue);
}
}
}
+ return $newValue;
}
/**
@@ -381,10 +391,7 @@ class Piwik_DataTable_Row
//same columns
$cols1 = $row1->getColumns();
$cols2 = $row2->getColumns();
-
- uksort($cols1, 'strnatcasecmp');
- uksort($cols2, 'strnatcasecmp');
- if($cols1 != $cols2)
+ if(array_diff($cols1, $cols2) !== array_diff($cols2, $cols1))
{
return false;
}
diff --git a/core/Date.php b/core/Date.php
index 450682df68..efcc526da4 100644
--- a/core/Date.php
+++ b/core/Date.php
@@ -41,6 +41,18 @@ class Piwik_Date
return new Piwik_Date($dateString);
}
+ protected $timestamp = null;
+
+ /**
+ * Returns the unix timestamp of the date
+ *
+ * @return int
+ */
+ public function getTimestamp()
+ {
+ return $this->timestamp;
+ }
+
/**
* Builds a Piwik_Date object
*
@@ -79,16 +91,6 @@ class Piwik_Date
}
/**
- * Returns the unix timestamp of the date
- *
- * @return int
- */
- public function getTimestamp()
- {
- return $this->timestamp;
- }
-
- /**
* Returns true if the current date is older than the given $date
*
* @param Piwik_Date $date
diff --git a/core/FrontController.php b/core/FrontController.php
index 2644f02938..718f4e997c 100644
--- a/core/FrontController.php
+++ b/core/FrontController.php
@@ -142,7 +142,6 @@ class Piwik_FrontController
{
throw new Exception("Action $action not found in the controller $controllerClassName.");
}
-
try {
return call_user_func_array( array($controller, $action ), $parameters);
} catch(Piwik_Access_NoAccessException $e) {
diff --git a/core/Period/Range.php b/core/Period/Range.php
index 03c97d3e23..d2cfb8dcf9 100644
--- a/core/Period/Range.php
+++ b/core/Period/Range.php
@@ -131,7 +131,6 @@ class Piwik_Period_Range extends Piwik_Period
{
throw new Exception("The date '$this->strDate' is not a date range. Should have the following format: 'lastN' or 'previousN' or 'YYYY-MM-DD,YYYY-MM-DD'.");
}
-
$endSubperiod = Piwik_Period::factory($this->strPeriod, $endDate);
$arrayPeriods= array();
diff --git a/core/Piwik.php b/core/Piwik.php
index 998d6da08b..9b2aa70801 100644
--- a/core/Piwik.php
+++ b/core/Piwik.php
@@ -423,7 +423,23 @@ class Piwik
static public function isNumeric($value)
{
- return !is_array($value) && ereg('^([-]{0,1}[0-9]{1,}[.]{0,1}[0-9]*)$', $value);
+ return is_numeric($value);
+ }
+
+ static public function getCurrency()
+ {
+ static $symbol = null;
+ if(is_null($symbol))
+ {
+ $symbol = Zend_Registry::get('config')->General->default_currency;
+ }
+ return $symbol;
+ }
+
+ static public function getPrettyMoney($value)
+ {
+ $symbol = self::getCurrency();
+ return sprintf("$symbol%.2f", $value);
}
static public function getPrettyTimeFromSeconds($numberOfSeconds)
@@ -664,7 +680,8 @@ class Piwik
period TINYINT UNSIGNED NULL,
ts_archived DATETIME NULL,
value FLOAT NULL,
- PRIMARY KEY(idarchive, name)
+ PRIMARY KEY(idarchive, name),
+ KEY `index_all` (`idsite`,`date1`,`date2`,`name`,`ts_archived`)
)
",
'archive_blob' => "CREATE TABLE {$prefixTables}archive_blob (
@@ -676,7 +693,8 @@ class Piwik
period TINYINT UNSIGNED NULL,
ts_archived DATETIME NULL,
value MEDIUMBLOB NULL,
- PRIMARY KEY(idarchive, name)
+ PRIMARY KEY(idarchive, name),
+ KEY `index_all` (`idsite`,`date1`,`date2`,`name`,`ts_archived`)
)
",
);
@@ -777,6 +795,11 @@ class Piwik
Zend_Registry::get('access')->checkUserHasSomeAdminAccess();
}
+ static public function checkUserHasSomeViewAccess()
+ {
+ Zend_Registry::get('access')->checkUserHasSomeViewAccess();
+ }
+
static public function isUserHasViewAccess( $idSites )
{
try{
diff --git a/core/Plugin.php b/core/Plugin.php
index f606751736..de3e3a7f72 100644
--- a/core/Plugin.php
+++ b/core/Plugin.php
@@ -71,15 +71,6 @@ abstract class Piwik_Plugin
}
/**
- * Returns the names of the required plugins
- * @var array
- */
- public function getListRequiredPlugins()
- {
- return array();
- }
-
- /**
* Returns the plugin name
* @var string
*/
diff --git a/core/SmartyPlugins/function.logoHtml.php b/core/SmartyPlugins/function.logoHtml.php
new file mode 100644
index 0000000000..85a57b02e3
--- /dev/null
+++ b/core/SmartyPlugins/function.logoHtml.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
+ * @version $Id$
+ *
+ * @package SmartyPlugins
+ */
+
+function smarty_function_logoHtml($params, &$smarty)
+{
+ if(!isset($params['metadata']['logo']))
+ {
+ return;
+ }
+ $width = $height = $alt = '';
+ if(isset($params['metadata']['logoWidth']))
+ {
+ $width = "width=".$params['metadata']['logoWidth'];
+ }
+ if(isset($params['metadata']['logoHeight']))
+ {
+ $height = "height=".$params['metadata']['logoHeight'];
+ }
+ if(isset($params['alt']))
+ {
+ $alt = "title='".$params['alt']."' alt='".$params['alt']."'";
+ }
+ return " <img $alt $width $height src=".$params['metadata']['logo']." />";
+}
diff --git a/core/SmartyPlugins/function.url.php b/core/SmartyPlugins/function.url.php
index adadea3beb..a837a8459b 100644
--- a/core/SmartyPlugins/function.url.php
+++ b/core/SmartyPlugins/function.url.php
@@ -1,31 +1,31 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: function.url.php 525 2008-06-25 23:49:13Z matt $
- *
- * @package SmartyPlugins
- */
-
-require_once "Url.php";
-
-/**
- * Smarty {url} function plugin.
- * Generates a piwik URL with the specified parameters modified.
- *
- * Examples:
- * <pre>
- * {url module="API"} will rewrite the URL modifying the module GET parameter
- * {url module="API" method="getKeywords"} will rewrite the URL modifying the parameters module=API method=getKeywords
- * </pre>
- *
- * @see Piwik_Url::getCurrentQueryStringWithParametersModified()
- * @param $name=$value of the parameters to modify in the generated URL
- * @return string Something like index.php?module=X&action=Y
- */
-function smarty_function_url($params, &$smarty)
-{
- return htmlspecialchars(Piwik_Url::getCurrentScriptName() . Piwik_Url::getCurrentQueryStringWithParametersModified( $params ));
-}
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: function.url.php 525 2008-06-25 23:49:13Z matt $
+ *
+ * @package SmartyPlugins
+ */
+
+require_once "Url.php";
+
+/**
+ * Smarty {url} function plugin.
+ * Generates a piwik URL with the specified parameters modified.
+ *
+ * Examples:
+ * <pre>
+ * {url module="API"} will rewrite the URL modifying the module GET parameter
+ * {url module="API" method="getKeywords"} will rewrite the URL modifying the parameters module=API method=getKeywords
+ * </pre>
+ *
+ * @see Piwik_Url::getCurrentQueryStringWithParametersModified()
+ * @param $name=$value of the parameters to modify in the generated URL
+ * @return string Something like index.php?module=X&action=Y
+ */
+function smarty_function_url($params, &$smarty)
+{
+ return htmlspecialchars(Piwik_Url::getCurrentScriptName() . Piwik_Url::getCurrentQueryStringWithParametersModified( $params ));
+}
diff --git a/core/Timer.php b/core/Timer.php
index 783dcff6ea..07c2adbd01 100644
--- a/core/Timer.php
+++ b/core/Timer.php
@@ -29,12 +29,12 @@ class Piwik_Timer
$this->memoryStart = $this->getMemoryUsage();
}
- public function getTime($decimals = 2)
+ public function getTime($decimals = 3)
{
return number_format($this->getMicrotime() - $this->timerStart, $decimals, '.', '');
}
- public function getTimeMs($decimals = 2)
+ public function getTimeMs($decimals = 3)
{
return number_format(1000*($this->getMicrotime() - $this->timerStart), $decimals, '.', '');
}
diff --git a/core/Tracker.php b/core/Tracker.php
index 171871efe3..5c3b52e8a3 100644
--- a/core/Tracker.php
+++ b/core/Tracker.php
@@ -11,29 +11,10 @@
/**
* Class used by the logging script piwik.php called by the javascript tag.
- * Handles the visitor & his/her actions on the website, saves the data in the DB, saves information in the cookie, etc.
+ * Handles the visitor & his/her actions on the website, saves the data in the DB,
+ * saves information in the cookie, etc.
*
- * To maximise the performance of the logging module, we use different techniques.
- *
- * On the PHP-only side:
- * - minimize the number of external files included.
- * Ideally only one (the configuration file) in all the normal cases.
- * We load the Loggers only when an error occurs ; this error is logged in the DB/File/etc
- * depending on the loggers settings in the configuration file.
- * - we may have to include external classes but we try to include only very
- * simple code without any dependency, so that we could simply write a script
- * that would merge all this simple code into a big piwik.php file.
- *
- * On the Database-related side:
- * - write all the SQL queries without using any DB abstraction layer. Manual filtering of input values.
- * - minimize the number of SQL queries necessary to complete the algorithm.
- * - carefully index the tables used
- * - try to have fixed length rows
- *
- * [ - use a partitionning by date for the tables ]
- *
- * Configuration options for the statsLogEngine module:
- * - use_cookie ; defines if we try to get/set a cookie to help recognize a unique visitor
+ * We try to include as little files as possible (no dependency on 3rd party modules).
*
* @package Piwik_Tracker
*/
@@ -57,6 +38,12 @@ class Piwik_Tracker
const COOKIE_INDEX_TIMESTAMP_FIRST_ACTION = 3;
const COOKIE_INDEX_ID_VISIT = 4;
const COOKIE_INDEX_ID_LAST_ACTION = 5;
+ const COOKIE_INDEX_REFERER_ID_VISIT = 6;
+ const COOKIE_INDEX_REFERER_TIMESTAMP = 7;
+ const COOKIE_INDEX_REFERER_TYPE = 8;
+ const COOKIE_INDEX_REFERER_NAME = 9;
+ const COOKIE_INDEX_REFERER_KEYWORD = 10;
+ const COOKIE_INDEX_VISITOR_RETURNING = 11;
public function __construct() {}
@@ -68,15 +55,27 @@ class Piwik_Tracker
{
try {
self::connectDatabase();
+
$visit = $this->getNewVisitObject();
$visit->handle();
+ unset($visit);
} catch (PDOException $e) {
$this->setState(self::STATE_LOGGING_DISABLE);
- }
+ }
}
$this->end();
}
+ /**
+ * Returns the date in the "Y-m-d H:i:s" PHP format
+ * @return string
+ */
+ public static function getDatetimeFromTimestamp($timestamp)
+ {
+ return date("Y-m-d H:i:s", $timestamp);
+ }
+
+
protected function init()
{
$this->loadTrackerPlugins();
@@ -155,7 +154,10 @@ class Piwik_Tracker
self::$db = $db;
}
- public static function getDb()
+ /**
+ * @return Piwik_Tracker_Db
+ */
+ public static function getDatabase()
{
return self::$db;
}
@@ -188,7 +190,6 @@ class Piwik_Tracker
throw new Exception("The Visit object set in the plugin must implement Piwik_Tracker_Visit_Interface");
}
- $visit->setDb(self::$db);
return $visit;
}
diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php
index a50baa06b4..970f2c0189 100644
--- a/core/Tracker/Action.php
+++ b/core/Tracker/Action.php
@@ -16,7 +16,7 @@
* @package Piwik_Tracker
*/
interface Piwik_Tracker_Action_Interface {
- public function getActionId();
+ public function getIdAction();
public function record( $idVisit, $idRefererAction, $timeSpentRefererAction );
public function setIdSite( $idSite );
}
@@ -45,11 +45,12 @@ interface Piwik_Tracker_Action_Interface {
*/
class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
{
- private $actionName;
private $url;
- private $defaultActionName;
- private $nameDownloadOutlink;
private $idSite;
+ private $idLinkVisitAction;
+ private $finalActionName;
+ private $actionType;
+ private $idAction = null;
/**
* 3 types of action, Standard action / Download / Outlink click
@@ -58,28 +59,20 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
const TYPE_DOWNLOAD = 3;
const TYPE_OUTLINK = 2;
+ protected function getDefaultActionName()
+ {
+ return Piwik_Tracker_Config::getInstance()->Tracker['default_action_name'];
+ }
+
/**
- * @param Piwik_Tracker_Db Database object to be used
+ * Returns URL of the page currently being tracked, or the file being downloaded, or the outlink being clicked
+ * @return string
*/
- function __construct( $db )
+ public function getUrl()
{
- $this->actionName = Piwik_Common::getRequestVar( 'action_name', '', 'string');
-
- $downloadVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_url_var_name'];
- $this->downloadUrl = Piwik_Common::getRequestVar( $downloadVariableName, '', 'string');
-
- $outlinkVariableName = Piwik_Tracker_Config::getInstance()->Tracker['outlink_url_var_name'];
- $this->outlinkUrl = Piwik_Common::getRequestVar( $outlinkVariableName, '', 'string');
-
- $nameVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_outlink_name_var'];
- $this->nameDownloadOutlink = Piwik_Common::getRequestVar( $nameVariableName, '', 'string');
-
- $this->url = Piwik_Common::getRequestVar( 'url', '', 'string');
- $this->db = $db;
- $this->defaultActionName = Piwik_Tracker_Config::getInstance()->Tracker['default_action_name'];
+ return $this->url;
}
-
/**
* Returns the idaction of the current action name.
* This idaction is used in the visitor logging table to link the visit information
@@ -91,9 +84,12 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
*
* @return int Id action that is associated to this action name in the Actions table lookup
*/
- function getActionId()
+ function getIdAction()
{
- $this->loadActionId();
+ if(is_null($this->idAction))
+ {
+ $this->idAction = $this->loadActionId();
+ }
return $this->idAction;
}
@@ -116,16 +112,16 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
*/
public function record( $idVisit, $idRefererAction, $timeSpentRefererAction)
{
- $this->db->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ".$this->db->prefixTable('log_link_visit_action')
+ Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ".Piwik_Tracker::getDatabase()->prefixTable('log_link_visit_action')
." (idvisit, idaction, idaction_ref, time_spent_ref_action) VALUES (?,?,?,?)",
- array($idVisit, $this->idAction, $idRefererAction, $timeSpentRefererAction)
+ array($idVisit, $this->getIdAction(), $idRefererAction, $timeSpentRefererAction)
);
- $idLinkVisitAction = $this->db->lastInsertId();
+ $this->idLinkVisitAction = Piwik_Tracker::getDatabase()->lastInsertId();
$info = array(
'idSite' => $this->idSite,
- 'idLinkVistAction' => $idLinkVisitAction,
+ 'idLinkVisitAction' => $this->idLinkVisitAction,
'idVisit' => $idVisit,
'idRefererAction' => $idRefererAction,
'timeSpentRefererAction' => $timeSpentRefererAction,
@@ -137,6 +133,16 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
Piwik_PostEvent('Tracker.Action.record', $this, $info);
}
+ /**
+ * Returns the ID of the newly created record in the log_link_visit_action table
+ *
+ * @return int | false
+ */
+ public function getIdLinkVisitAction()
+ {
+ return $this->idLinkVisitAction;
+ }
+
/**
* Generates the name of the action from the URL or the specified name.
* Sets the name as $this->finalActionName
@@ -146,34 +152,44 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
private function generateInfo()
{
$actionName = '';
- if(!empty($this->downloadUrl))
+
+ $downloadVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_url_var_name'];
+ $downloadUrl = Piwik_Common::getRequestVar( $downloadVariableName, '', 'string');
+
+ if(!empty($downloadUrl))
{
$this->actionType = self::TYPE_DOWNLOAD;
- $url = $this->downloadUrl;
- //$actionName = $this->nameDownloadOutlink;
+ $url = $downloadUrl;
$actionName = $url;
}
- elseif(!empty($this->outlinkUrl))
+ else
{
- $this->actionType = self::TYPE_OUTLINK;
- $url = $this->outlinkUrl;
- //remove the last '/' character if it's present
- if(substr($url,-1) == '/')
+ $outlinkVariableName = Piwik_Tracker_Config::getInstance()->Tracker['outlink_url_var_name'];
+ $outlinkUrl = Piwik_Common::getRequestVar( $outlinkVariableName, '', 'string');
+ if(!empty($outlinkUrl))
{
- $url = substr($url,0,-1);
+ $this->actionType = self::TYPE_OUTLINK;
+ $url = $outlinkUrl;
+ //remove the last '/' character if it's present
+ if(substr($url,-1) == '/')
+ {
+ $url = substr($url,0,-1);
+ }
+ $nameVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_outlink_name_var'];
+ $actionName = Piwik_Common::getRequestVar( $nameVariableName, '', 'string');
+ if( empty($actionName) )
+ {
+ $actionName = $url;
+ }
}
- $actionName = $this->nameDownloadOutlink;
- if( empty($actionName) )
+ else
{
- $actionName = $url;
+ $this->actionType = self::TYPE_ACTION;
+ $url = Piwik_Common::getRequestVar( 'url', '', 'string');
+ $actionName = Piwik_Common::getRequestVar( 'action_name', '', 'string');
}
}
- else
- {
- $this->actionType = self::TYPE_ACTION;
- $url = $this->url;
- $actionName = $this->actionName;
- }
+ $this->url = $url;
// the ActionName wasn't specified
if( empty($actionName) )
@@ -188,7 +204,7 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
&& $actionName[strlen($actionName)-1] == '/'
)
{
- $actionName.=$this->defaultActionName;
+ $actionName .= $this->getDefaultActionName();
}
}
@@ -224,7 +240,7 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
if(empty($actionName))
{
- $actionName = $this->defaultActionName;
+ $actionName = $this->getDefaultActionName();
}
$this->finalActionName = $actionName;
@@ -233,17 +249,17 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
/**
* Sets the attribute $idAction based on $finalActionName and $actionType.
*
- * @see getActionId()
+ * @see getIdAction()
*/
private function loadActionId()
- {
+ {
$this->generateInfo();
$name = $this->finalActionName;
$type = $this->actionType;
- $idAction = $this->db->fetch("/* SHARDING_ID_SITE = ".$this->idSite." */ SELECT idaction
- FROM ".$this->db->prefixTable('log_action')
+ $idAction = Piwik_Tracker::getDatabase()->fetch("/* SHARDING_ID_SITE = ".$this->idSite." */ SELECT idaction
+ FROM ".Piwik_Tracker::getDatabase()->prefixTable('log_action')
." WHERE name = ? AND type = ?",
array($name, $type)
);
@@ -251,16 +267,18 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
// the action name has not been found, create it
if($idAction === false)
{
- $this->db->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ". $this->db->prefixTable('log_action'). "( name, type )
- VALUES (?,?)",array($name,$type) );
- $idAction = $this->db->lastInsertId();
+ Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ".$this->idSite." */
+ INSERT INTO ". Piwik_Tracker::getDatabase()->prefixTable('log_action'). "( name, type )
+ VALUES (?,?)",
+ array($name,$type)
+ );
+ $idAction = Piwik_Tracker::getDatabase()->lastInsertId();
}
else
{
$idAction = $idAction['idaction'];
}
-
- $this->idAction = $idAction;
+ return $idAction;
}
}
diff --git a/core/Tracker/Generator.php b/core/Tracker/Generator.php
index 0979b02fea..8a11a7028c 100644
--- a/core/Tracker/Generator.php
+++ b/core/Tracker/Generator.php
@@ -355,7 +355,6 @@ class Piwik_Tracker_Generator
for($i = 0; $i < $nbVisitors; $i++)
{
$nbActions = mt_rand(1, $nbActionsMaxPerVisit);
-
Piwik_Tracker_Generator_Visit::setTimestampToUse($this->getTimestampToUse());
$this->generateNewVisit();
@@ -364,7 +363,6 @@ class Piwik_Tracker_Generator
$this->generateActionVisit();
$this->saveVisit();
}
-
$nbActionsTotal += $nbActions;
}
return $nbActionsTotal;
@@ -655,6 +653,7 @@ class Piwik_Tracker_Generator
$this->setFakeRequest();
$process = new Piwik_Tracker_Generator_Tracker;
$process->main();
+ unset($process);
}
}
diff --git a/core/Tracker/Generator/Tracker.php b/core/Tracker/Generator/Tracker.php
index d4457c33fc..4344e2a515 100644
--- a/core/Tracker/Generator/Tracker.php
+++ b/core/Tracker/Generator/Tracker.php
@@ -47,7 +47,6 @@ class Piwik_Tracker_Generator_Tracker extends Piwik_Tracker
protected function getNewVisitObject()
{
$visit = new Piwik_Tracker_Generator_Visit();
- $visit->setDb(self::$db);
return $visit;
}
diff --git a/core/Tracker/Generator/Visit.php b/core/Tracker/Generator/Visit.php
index 41535f045c..533b0963f5 100644
--- a/core/Tracker/Generator/Visit.php
+++ b/core/Tracker/Generator/Visit.php
@@ -37,11 +37,6 @@ class Piwik_Tracker_Generator_Visit extends Piwik_Tracker_Visit
self::$timestampToUse += mt_rand(4,1840);
return self::$timestampToUse;
}
-
- protected function getDatetimeFromTimestamp($timestamp)
- {
- return date("Y-m-d H:i:s",$timestamp);
- }
protected function updateCookie()
{
@@ -49,3 +44,4 @@ class Piwik_Tracker_Generator_Visit extends Piwik_Tracker_Visit
}
}
+
diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php
new file mode 100644
index 0000000000..477339ad0e
--- /dev/null
+++ b/core/Tracker/GoalManager.php
@@ -0,0 +1,147 @@
+<?php
+
+class Piwik_Tracker_GoalManager
+{
+ /**
+ * @var Piwik_Cookie
+ */
+ protected $cookie = null;
+ /**
+ * @var Piwik_Tracker_Action
+ */
+ protected $action = null;
+ protected $matchedGoals = array();
+ protected $idsite = null;
+
+ function __construct($action)
+ {
+ $this->action = $action;
+
+
+ }
+
+ function setCookie($cookie)
+ {
+ $this->cookie = $cookie;
+ }
+
+ //TODO goalid should be incrementing on a website basis
+ // load goal definitions from file
+ static public function getGoalDefinitions()
+ {
+ return array(
+ 0 => array( 'id' => 1,
+ 'name' => 'Downloads',
+ 'default_revenue' => '3',
+ 'pattern' => '/e/'
+ ),
+ 1 => array( 'id' => 5,
+ 'name' => 'hosted signups',
+ 'default_revenue' => false,
+ 'pattern' => '//'
+ ),
+ );
+ }
+
+ static public function getGoalDefinition( $idGoal )
+ {
+ $goals = self::getGoalDefinitions();
+ foreach($goals as $goal)
+ {
+ if($goal['id'] == $idGoal)
+ {
+ return $goal;
+ }
+ }
+ throw new Exception("The goal id = $idGoal couldn't be found.");
+ }
+
+ static public function getGoalIds()
+ {
+ $goals = self::getGoalDefinitions();
+ $goalIds = array();
+ foreach($goals as $goal)
+ {
+ $goalIds[] = $goal['id'];
+ }
+ return $goalIds;
+ }
+
+ //TODO does this code work for manually triggered goals, with custom revenue?
+ function detectGoals($idSite)
+ {
+ $url = $this->action->getUrl();
+ $goals = $this->getGoalDefinitions($idSite);
+ foreach($goals as $goal)
+ {
+ $match = preg_match($goal['pattern'], $url);
+ if($match === 1)
+ {
+ $this->matchedGoals[] = $goal;
+ }
+ }
+ return count($this->matchedGoals) > 0;
+ }
+
+ function recordGoals($visitorInformation)
+ {
+ $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Piwik_Common::getCountry(Piwik_Common::getBrowserLanguage());
+ $location_continent = isset($visitorInformation['location_continent']) ? $visitorInformation['location_continent'] : Piwik_Common::getContinent($location_country);
+
+ $goal = array(
+ 'idvisit' => $visitorInformation['idvisit'],
+ 'idsite' => $visitorInformation['idsite'],
+ 'visitor_idcookie' => $visitorInformation['visitor_idcookie'],
+ 'server_time' => Piwik_Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']),
+ 'visit_server_date' => $visitorInformation['visit_server_date'],
+ 'idaction' => $this->action->getIdAction(),
+ 'idlink_va' => $this->action->getIdLinkVisitAction(),
+ 'location_country' => $location_country,
+ 'location_continent'=> $location_continent,
+ 'url' => $this->action->getUrl(),
+ 'visitor_returning' => $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_VISITOR_RETURNING ),
+ );
+
+ $referer_idvisit = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_ID_VISIT );
+ if($referer_idvisit !== false)
+ {
+ $goal += array(
+ 'referer_idvisit' => $referer_idvisit,
+ 'referer_visit_server_date' => date("Y-m-d", $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_TIMESTAMP )),
+ 'referer_type' => htmlspecialchars_decode($this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_TYPE )),
+ 'referer_name' => htmlspecialchars_decode($this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_NAME )),
+ 'referer_keyword' => htmlspecialchars_decode($this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_KEYWORD )),
+ );
+ }
+
+ foreach($this->matchedGoals as $matchedGoal)
+ {
+ printDebug("- Goal ".$matchedGoal['id'] ." matched. Recording...");
+ $newGoal = $goal;
+ $newGoal['idgoal'] = $matchedGoal['id'];
+ $newGoal['revenue'] = $matchedGoal['default_revenue'];
+ printDebug($newGoal);
+
+ $fields = implode(", ", array_keys($newGoal));
+ $bindFields = substr(str_repeat( "?,",count($newGoal)),0,-1);
+
+ try {
+ Piwik_Tracker::getDatabase()->query(
+ "INSERT INTO " . Piwik_Tracker::getDatabase()->prefixTable('log_conversion') . " ($fields)
+ VALUES ($bindFields) ", array_values($newGoal)
+ );
+ } catch( Exception $e) {
+ if(strpos($e->getMessage(), '1062') !== false)
+ {
+ // integrity violation when same visit converts to the same goal twice
+ printDebug("--> Goal already recorded for this (idvisit, idgoal)");
+ }
+ else
+ {
+ throw $e;
+ }
+ }
+ //$idlog_goal = Piwik_Tracker::getDatabase()->lastInsertId();
+ }
+ }
+} \ No newline at end of file
diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php
index d7bcc8832d..087bb1a0fc 100644
--- a/core/Tracker/Visit.php
+++ b/core/Tracker/Visit.php
@@ -12,7 +12,6 @@
interface Piwik_Tracker_Visit_Interface {
function handle();
- function setDb($db);
}
/**
@@ -31,11 +30,14 @@ interface Piwik_Tracker_Visit_Interface {
class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
- protected $cookieLog = null;
+ /**
+ * @var Piwik_Cookie
+ */
+ protected $cookie = null;
protected $visitorInfo = array();
protected $userSettingsInformation = null;
- protected $db = null;
protected $idsite;
+ protected $visitorKnown;
function __construct()
{
@@ -48,9 +50,203 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
$this->idsite = $idsite;
}
- public function setDb($db)
+ /**
+ * Main algorith to handle the visit.
+ *
+ * Once we have the visitor information, we have to define if the visit is a new or a known visit.
+ *
+ * 1) When the last action was done more than 30min ago,
+ * or if the visitor is new, then this is a new visit.
+ *
+ * 2) If the last action is less than 30min ago, then the same visit is going on.
+ * Because the visit goes on, we can get the time spent during the last action.
+ *
+ * NB:
+ * - In the case of a new visit, then the time spent
+ * during the last action of the previous visit is unknown.
+ *
+ * - In the case of a new visit but with a known visitor,
+ * we can set the 'returning visitor' flag.
+ *
+ * In all the cases we set a cookie to the visitor with the new information.
+ */
+ public function handle()
+ {
+ if($this->isExcluded())
+ {
+ return;
+ }
+
+ // current action
+ $action = $this->newAction();
+ $actionId = $action->getIdAction();
+
+ // goal matched?
+ $goalManager = new Piwik_Tracker_GoalManager( $action );
+ $someGoalsConverted = false;
+ if($goalManager->detectGoals($this->idsite))
+ {
+ $someGoalsConverted = true;
+ }
+
+ // the visitor and session
+ $this->recognizeTheVisitor();
+ if( $this->isVisitorKnown()
+ && $this->isLastActionInTheSameVisit())
+ {
+ $this->handleKnownVisit($actionId, $someGoalsConverted);
+ $action->record( $this->visitorInfo['idvisit'],
+ $this->visitorInfo['visit_exit_idaction'],
+ $this->visitorInfo['time_spent_ref_action']
+ );
+ }
+ else
+ {
+ $this->handleNewVisit($actionId, $someGoalsConverted);
+ $action->record( $this->visitorInfo['idvisit'], 0, 0 );
+ }
+
+ // update the cookie with the new visit information
+ $this->updateCookie();
+
+ // record the goals if applicable
+ if($someGoalsConverted)
+ {
+ $goalManager->setCookie($this->cookie);
+ $goalManager->recordGoals($this->visitorInfo);
+ }
+ unset($goalManager);
+ unset($action);
+ }
+
+
+ /**
+ * In the case of a known visit, we have to do the following actions:
+ *
+ * 1) Insert the new action
+ *
+ * 2) Update the visit information
+ */
+ protected function handleKnownVisit($actionId, $someGoalsConverted)
+ {
+ printDebug("Visit known.");
+ $serverTime = $this->getCurrentTimestamp();
+ $datetimeServer = Piwik_Tracker::getDatetimeFromTimestamp($serverTime);
+
+ $sqlUpdateGoalConverted = '';
+ if($someGoalsConverted)
+ {
+ $sqlUpdateGoalConverted = " visit_goal_converted = 1,";
+ }
+
+ Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ". $this->idsite ." */
+ UPDATE ". Piwik_Tracker::getDatabase()->prefixTable('log_visit')."
+ SET visit_last_action_time = ?,
+ visit_exit_idaction = ?,
+ visit_total_actions = visit_total_actions + 1,
+ $sqlUpdateGoalConverted
+ visit_total_time = UNIX_TIMESTAMP(visit_last_action_time) - UNIX_TIMESTAMP(visit_first_action_time)
+ WHERE idvisit = ?
+ LIMIT 1",
+ array( $datetimeServer,
+ $actionId,
+ $this->visitorInfo['idvisit'] )
+ );
+ $this->visitorInfo['idsite'] = $this->idsite;
+ $this->visitorInfo['visit_server_date'] = $this->getCurrentDate();
+
+ // will be updated in cookie
+ $this->visitorInfo['visit_last_action_time'] = $serverTime;
+ $this->visitorInfo['visit_exit_idaction'] = $actionId;
+ $this->visitorInfo['time_spent_ref_action'] = $serverTime - $this->visitorInfo['visit_last_action_time'];
+ }
+
+ /**
+ * In the case of a new visit, we have to do the following actions:
+ *
+ * 1) Insert the new action
+ *
+ * 2) Insert the visit information
+ */
+ protected function handleNewVisit($actionId, $someGoalsConverted)
{
- $this->db = $db;
+ printDebug("New Visit.");
+
+ $localTime = Piwik_Common::getRequestVar( 'h', $this->getCurrentDate("H"), 'numeric')
+ .':'. Piwik_Common::getRequestVar( 'm', $this->getCurrentDate("i"), 'numeric')
+ .':'. Piwik_Common::getRequestVar( 's', $this->getCurrentDate("s"), 'numeric');
+ $serverTime = $this->getCurrentTimestamp();
+ $serverDate = $this->getCurrentDate();
+
+ if($this->isVisitorKnown())
+ {
+ $idcookie = $this->visitorInfo['visitor_idcookie'];
+ $returningVisitor = 1;
+ }
+ else
+ {
+ $idcookie = $this->getVisitorUniqueId();
+ $returningVisitor = 0;
+ }
+
+ $defaultTimeOnePageVisit = Piwik_Tracker_Config::getInstance()->Tracker['default_time_one_page_visit'];
+
+ $userInfo = $this->getUserSettingsInformation();
+ $country = Piwik_Common::getCountry($userInfo['location_browser_lang']);
+ $refererInfo = $this->getRefererInformation();
+
+ /**
+ * Save the visitor
+ */
+ $this->visitorInfo = array(
+ 'idsite' => $this->idsite,
+ 'visitor_localtime' => $localTime,
+ 'visitor_idcookie' => $idcookie,
+ 'visitor_returning' => $returningVisitor,
+ 'visit_first_action_time' => Piwik_Tracker::getDatetimeFromTimestamp($serverTime),
+ 'visit_last_action_time' => Piwik_Tracker::getDatetimeFromTimestamp($serverTime),
+ 'visit_server_date' => $serverDate,
+ 'visit_entry_idaction' => $actionId,
+ 'visit_exit_idaction' => $actionId,
+ 'visit_total_actions' => 1,
+ 'visit_total_time' => $defaultTimeOnePageVisit,
+ 'visit_goal_converted' => $someGoalsConverted ? 1: 0,
+ 'referer_type' => $refererInfo['referer_type'],
+ 'referer_name' => $refererInfo['referer_name'],
+ 'referer_url' => $refererInfo['referer_url'],
+ 'referer_keyword' => $refererInfo['referer_keyword'],
+ 'config_md5config' => $userInfo['config_md5config'],
+ 'config_os' => $userInfo['config_os'],
+ 'config_browser_name' => $userInfo['config_browser_name'],
+ 'config_browser_version' => $userInfo['config_browser_version'],
+ 'config_resolution' => $userInfo['config_resolution'],
+ 'config_pdf' => $userInfo['config_pdf'],
+ 'config_flash' => $userInfo['config_flash'],
+ 'config_java' => $userInfo['config_java'],
+ 'config_director' => $userInfo['config_director'],
+ 'config_quicktime' => $userInfo['config_quicktime'],
+ 'config_realplayer' => $userInfo['config_realplayer'],
+ 'config_windowsmedia' => $userInfo['config_windowsmedia'],
+ 'config_cookie' => $userInfo['config_cookie'],
+ 'location_ip' => $userInfo['location_ip'],
+ 'location_browser_lang' => $userInfo['location_browser_lang'],
+ 'location_country' => $country
+ );
+
+ Piwik_PostEvent('Tracker.newVisitorInformation', $this->visitorInfo);
+ $this->visitorInfo['location_continent'] = Piwik_Common::getContinent( $this->visitorInfo['location_country'] );
+
+ $fields = implode(", ", array_keys($this->visitorInfo));
+ $values = substr(str_repeat( "?,",count($this->visitorInfo)),0,-1);
+
+ Piwik_Tracker::getDatabase()->query( "INSERT INTO ".Piwik_Tracker::getDatabase()->prefixTable('log_visit').
+ " ($fields) VALUES ($values)", array_values($this->visitorInfo));
+
+ $idVisit = Piwik_Tracker::getDatabase()->lastInsertId();
+
+ $this->visitorInfo['idvisit'] = $idVisit;
+ $this->visitorInfo['visit_first_action_time'] = $serverTime;
+ $this->visitorInfo['visit_last_action_time'] = $serverTime;
}
/**
@@ -70,15 +266,6 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
return time();
}
-
- /**
- * Returns the date in the "Y-m-d H:i:s" PHP format
- * @return string
- */
- protected function getDatetimeFromTimestamp($timestamp)
- {
- return date("Y-m-d H:i:s", $timestamp);
- }
/**
* Test if the current visitor is excluded from the statistics.
@@ -144,19 +331,18 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
protected function recognizeTheVisitor()
{
$this->visitorKnown = false;
+ $this->cookie = new Piwik_Cookie( $this->getCookieName() );
- $this->cookieLog = new Piwik_Cookie( $this->getCookieName() );
/*
* Case the visitor has the piwik cookie.
* We make sure all the data that should saved in the cookie is available.
*/
-
- if( false !== ($idVisitor = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_IDVISITOR )) )
+ if( false !== ($idVisitor = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_IDVISITOR )) )
{
- $timestampLastAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION );
- $timestampFirstAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION );
- $idVisit = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_ID_VISIT );
- $idLastAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION );
+ $timestampLastAction = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION );
+ $timestampFirstAction = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION );
+ $idVisit = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_ID_VISIT );
+ $idLastAction = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION );
if( $timestampLastAction !== false && is_numeric($timestampLastAction)
&& $timestampFirstAction !== false && is_numeric($timestampFirstAction)
@@ -177,21 +363,22 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
}
/*
- * If the visitor doesn't have the piwik cookie, we look for a visitor that has exactly the same configuration
- * and that visited the website today.
+ * If the visitor doesn't have the piwik cookie, we look for a visitor
+ * that has exactly the same configuration and that visited the website today.
*/
- if( !$this->visitorKnown )
+ if( !$this->visitorKnown
+ && Piwik_Tracker_Config::getInstance()->Tracker['enable_detect_unique_visitor_using_settings'])
{
$userInfo = $this->getUserSettingsInformation();
$md5Config = $userInfo['config_md5config'];
- $visitRow = $this->db->fetch(
+ $visitRow = Piwik_Tracker::getDatabase()->fetch(
" SELECT visitor_idcookie,
UNIX_TIMESTAMP(visit_last_action_time) as visit_last_action_time,
UNIX_TIMESTAMP(visit_first_action_time) as visit_first_action_time,
idvisit,
visit_exit_idaction
- FROM ".$this->db->prefixTable('log_visit').
+ FROM ".Piwik_Tracker::getDatabase()->prefixTable('log_visit').
" WHERE visit_server_date = ?
AND idsite = ?
AND config_md5config = ?
@@ -226,8 +413,6 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
return $this->userSettingsInformation;
}
-
-
$plugin_Flash = Piwik_Common::getRequestVar( 'fla', 0, 'int');
$plugin_Director = Piwik_Common::getRequestVar( 'dir', 0, 'int');
$plugin_Quicktime = Piwik_Common::getRequestVar( 'qt', 0, 'int');
@@ -249,7 +434,7 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
$ip = Piwik_Common::getIp();
$ip = ip2long($ip);
- $browserLang = substr(Piwik_Common::getBrowserLanguage(), 0, 20);
+ $browserLang = Piwik_Common::getBrowserLanguage();
$configurationHash = $this->getConfigHash(
$os,
@@ -305,47 +490,6 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
return $this->visitorKnown === true;
}
- /**
- * Main algorith to handle the visit.
- *
- * Once we have the visitor information, we have to define if the visit is a new or a known visit.
- *
- * 1) When the last action was done more than 30min ago,
- * or if the visitor is new, then this is a new visit.
- *
- * 2) If the last action is less than 30min ago, then the same visit is going on.
- * Because the visit goes on, we can get the time spent during the last action.
- *
- * NB:
- * - In the case of a new visit, then the time spent
- * during the last action of the previous visit is unknown.
- *
- * - In the case of a new visit but with a known visitor,
- * we can set the 'returning visitor' flag.
- *
- * In all the cases we set a cookie to the visitor with the new information.
- */
- public function handle()
- {
- if($this->isExcluded())
- {
- return;
- }
-
- $this->recognizeTheVisitor();
- if( $this->isVisitorKnown()
- && $this->isLastActionInTheSameVisit())
- {
- $this->handleKnownVisit();
- }
- else
- {
- $this->handleNewVisit();
- }
-
- // we update the cookie with the new visit information
- $this->updateCookie();
- }
/**
* Update the cookie information.
@@ -354,190 +498,50 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
printDebug("We manage the cookie...");
+ if( isset($this->visitorInfo['referer_type'])
+ && $this->visitorInfo['referer_type'] != Piwik_Common::REFERER_TYPE_DIRECT_ENTRY)
+ {
+ // if the setting is set to use only the first referer,
+ // we don't update the cookie referer values if they are already set
+ if( !Piwik_Tracker_Config::getInstance()->Tracker['use_first_referer_to_determine_goal_referer']
+ || $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_TYPE ) == false)
+ {
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_TYPE, $this->visitorInfo['referer_type']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_NAME, $this->visitorInfo['referer_name']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_KEYWORD, $this->visitorInfo['referer_keyword']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_ID_VISIT, $this->visitorInfo['idvisit']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_TIMESTAMP, $this->getCurrentTimestamp()) ;
+ }
+ }
+
// idcookie has been generated in handleNewVisit or we simply propagate the old value
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_IDVISITOR,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_IDVISITOR,
$this->visitorInfo['visitor_idcookie'] );
// the last action timestamp is the current timestamp
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION,
$this->visitorInfo['visit_last_action_time'] );
// the first action timestamp is the timestamp of the first action of the current visit
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION,
$this->visitorInfo['visit_first_action_time'] );
// the idvisit has been generated by mysql in handleNewVisit or simply propagated here
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_ID_VISIT,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_ID_VISIT,
$this->visitorInfo['idvisit'] );
// the last action ID is the current exit idaction
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION,
$this->visitorInfo['visit_exit_idaction'] );
-
- $this->cookieLog->save();
- }
-
-
- /**
- * In the case of a known visit, we have to do the following actions:
- *
- * 1) Insert the new action
- *
- * 2) Update the visit information
- */
- protected function handleKnownVisit()
- {
- printDebug("Visit known.");
-
- /**
- * Init the action
- */
- $action = $this->getActionObject();
- $actionId = $action->getActionId();
- printDebug("idAction = $actionId");
-
- $serverTime = $this->getCurrentTimestamp();
- $datetimeServer = $this->getDatetimeFromTimestamp($serverTime);
-
- $this->db->query("/* SHARDING_ID_SITE = ". $this->idsite ." */
- UPDATE ". $this->db->prefixTable('log_visit')."
- SET visit_last_action_time = ?,
- visit_exit_idaction = ?,
- visit_total_actions = visit_total_actions + 1,
- visit_total_time = UNIX_TIMESTAMP(visit_last_action_time) - UNIX_TIMESTAMP(visit_first_action_time)
- WHERE idvisit = ?
- LIMIT 1",
- array( $datetimeServer,
- $actionId,
- $this->visitorInfo['idvisit'] )
- );
- /**
- * Save the action
- */
- $timespentLastAction = $serverTime - $this->visitorInfo['visit_last_action_time'];
-
- $action->record( $this->visitorInfo['idvisit'],
- $this->visitorInfo['visit_exit_idaction'],
- $timespentLastAction
- );
-
-
- /**
- * Cookie fields to be updated
- */
- $this->visitorInfo['visit_last_action_time'] = $serverTime;
- $this->visitorInfo['visit_exit_idaction'] = $actionId;
-
- }
-
- /**
- * In the case of a new visit, we have to do the following actions:
- *
- * 1) Insert the new action
- *
- * 2) Insert the visit information
- */
- protected function handleNewVisit()
- {
- printDebug("New Visit.");
-
- /**
- * Get the variables from the REQUEST
- */
- $localTime = Piwik_Common::getRequestVar( 'h', $this->getCurrentDate("H"), 'numeric')
- .':'. Piwik_Common::getRequestVar( 'm', $this->getCurrentDate("i"), 'numeric')
- .':'. Piwik_Common::getRequestVar( 's', $this->getCurrentDate("s"), 'numeric');
-
- $serverTime = $this->getCurrentTimestamp();
- $serverDate = $this->getCurrentDate();
-
- if($this->isVisitorKnown())
- {
- $idcookie = $this->visitorInfo['visitor_idcookie'];
- $returningVisitor = 1;
- }
- else
+ // for a new visit, we flag the visit with visitor_returning
+ if(isset($this->visitorInfo['visitor_returning']))
{
- $idcookie = $this->getVisitorUniqueId();
- $returningVisitor = 0;
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_VISITOR_RETURNING,
+ $this->visitorInfo['visitor_returning'] );
}
- $defaultTimeOnePageVisit = Piwik_Tracker_Config::getInstance()->Tracker['default_time_one_page_visit'];
-
- $userInfo = $this->getUserSettingsInformation();
- $country = Piwik_Common::getCountry($userInfo['location_browser_lang']);
-
- $refererInfo = $this->getRefererInformation();
-
- /**
- * Init the action
- */
- $action = $this->getActionObject();
- $actionId = $action->getActionId();
-
- printDebug("idAction = $actionId");
-
-
- /**
- * Save the visitor
- */
- $informationToSave = array(
- 'idsite' => $this->idsite,
- 'visitor_localtime' => $localTime,
- 'visitor_idcookie' => $idcookie,
- 'visitor_returning' => $returningVisitor,
- 'visit_first_action_time' => $this->getDatetimeFromTimestamp($serverTime),
- 'visit_last_action_time' => $this->getDatetimeFromTimestamp($serverTime),
- 'visit_server_date' => $serverDate,
- 'visit_entry_idaction' => $actionId,
- 'visit_exit_idaction' => $actionId,
- 'visit_total_actions' => 1,
- 'visit_total_time' => $defaultTimeOnePageVisit,
- 'referer_type' => $refererInfo['referer_type'],
- 'referer_name' => $refererInfo['referer_name'],
- 'referer_url' => $refererInfo['referer_url'],
- 'referer_keyword' => $refererInfo['referer_keyword'],
- 'config_md5config' => $userInfo['config_md5config'],
- 'config_os' => $userInfo['config_os'],
- 'config_browser_name' => $userInfo['config_browser_name'],
- 'config_browser_version' => $userInfo['config_browser_version'],
- 'config_resolution' => $userInfo['config_resolution'],
- 'config_pdf' => $userInfo['config_pdf'],
- 'config_flash' => $userInfo['config_flash'],
- 'config_java' => $userInfo['config_java'],
- 'config_director' => $userInfo['config_director'],
- 'config_quicktime' => $userInfo['config_quicktime'],
- 'config_realplayer' => $userInfo['config_realplayer'],
- 'config_windowsmedia' => $userInfo['config_windowsmedia'],
- 'config_cookie' => $userInfo['config_cookie'],
- 'location_ip' => $userInfo['location_ip'],
- 'location_browser_lang' => $userInfo['location_browser_lang'],
- 'location_country' => $country
- );
-
- Piwik_PostEvent('Tracker.newVisitorInformation', $informationToSave);
- $informationToSave['location_continent'] = Piwik_Common::getContinent( $informationToSave['location_country'] );
-
- $fields = implode(", ", array_keys($informationToSave));
- $values = substr(str_repeat( "?,",count($informationToSave)),0,-1);
-
- $this->db->query( "INSERT INTO ".$this->db->prefixTable('log_visit').
- " ($fields) VALUES ($values)", array_values($informationToSave));
-
- $idVisit = $this->db->lastInsertId();
-
- // Update the visitor information attribute with this information array
- $this->visitorInfo = $informationToSave;
- $this->visitorInfo['idvisit'] = $idVisit;
-
- // we have to save timestamp in the object properties, whereas mysql eats some other datetime format
- $this->visitorInfo['visit_first_action_time'] = $serverTime;
- $this->visitorInfo['visit_last_action_time'] = $serverTime;
-
- // saves the action
- $action->record( $idVisit, 0, 0 );
-
+ $this->cookie->save();
}
/**
@@ -546,14 +550,14 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
*
* @return Piwik_Tracker_Action child or fake but with same public interface
*/
- protected function getActionObject()
+ protected function newAction()
{
$action = null;
Piwik_PostEvent('Tracker.newAction', $action);
if(is_null($action))
{
- $action = new Piwik_Tracker_Action( $this->db );
+ $action = new Piwik_Tracker_Action();
}
elseif(!($action instanceof Piwik_Tracker_Action_Interface))
{
diff --git a/core/Updates/0.2.28.php b/core/Updates/0.2.28.php
new file mode 100644
index 0000000000..a64b2b2a72
--- /dev/null
+++ b/core/Updates/0.2.28.php
@@ -0,0 +1,9 @@
+<?php
+
+Piwik_Query( "ALTER TABLE `".Piwik::prefixTable('log_visit')."`
+ ADD `visit_goal_converted` VARCHAR( 1 ) NOT NULL AFTER `visit_total_time` ;");
+
+//TODO
+// alter all archive_*
+// KEY `index_all` (`idsite`,`date1`,`date2`,`name`,`ts_archived`)
+
diff --git a/core/Version.php b/core/Version.php
index d54b22b973..89ad548c01 100644
--- a/core/Version.php
+++ b/core/Version.php
@@ -1,4 +1,4 @@
-<?php
+<?php
final class Piwik_Version {
const VERSION = '0.2.26';
diff --git a/core/View.php b/core/View.php
index 5d62bd0aa1..7a1a6479c2 100644
--- a/core/View.php
+++ b/core/View.php
@@ -9,7 +9,6 @@
* @package Piwik_Visualization
*/
-require_once "Smarty.php";
require_once "iView.php";
/**
@@ -25,6 +24,7 @@ class Piwik_View implements Piwik_iView
public function __construct( $templateFile, $smConf = array())
{
+ require_once "Smarty.php";
$this->template = $templateFile;
$this->smarty = new Piwik_Smarty();
diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php
index c91a200e00..cc767a1337 100644
--- a/core/ViewDataTable.php
+++ b/core/ViewDataTable.php
@@ -93,13 +93,13 @@ abstract class Piwik_ViewDataTable
* @see init()
* @var string
*/
- protected $actionToLoadTheSubTable = null;
+ protected $controllerActionCalledWhenRequestSubTable = null;
/**
* @see init()
* @var string
*/
- protected $moduleNameAndMethod;
+ protected $apiMethodToRequestDataTable;
/**
* This view should be an implementation of the Interface Piwik_iView
@@ -197,6 +197,11 @@ abstract class Piwik_ViewDataTable
return new Piwik_ViewDataTable_HtmlTable_AllColumns();
break;
+ case 'tableGoals':
+ require_once "ViewDataTable/HtmlTable/Goals.php";
+ return new Piwik_ViewDataTable_HtmlTable_Goals();
+ break;
+
case 'table':
default:
require_once "ViewDataTable/HtmlTable.php";
@@ -208,42 +213,45 @@ abstract class Piwik_ViewDataTable
/**
* Inits the object given the $currentControllerName, $currentControllerAction of
* the calling controller action, eg. 'Referers' 'getLongListOfKeywords'.
- * The initialization also requires the $moduleNameAndMethod of the API method
+ * The initialization also requires the $apiMethodToRequestDataTable of the API method
* to call in order to get the DataTable, eg. 'Referers.getKeywords'.
- * The optional $actionToLoadTheSubTable defines the method name of the API to call when there is a idSubtable.
+ * The optional $controllerActionCalledWhenRequestSubTable defines the method name of the API to call when there is a idSubtable.
* This value would be used by the javascript code building the GET request to the API.
*
* Example:
* For the keywords listing, a click on the row loads the subTable of the Search Engines for this row.
- * In this case $actionToLoadTheSubTable = 'getSearchEnginesFromKeywordId'.
+ * In this case $controllerActionCalledWhenRequestSubTable = 'getSearchEnginesFromKeywordId'.
* The GET request will hit 'Referers.getSearchEnginesFromKeywordId'.
*
* @param string $currentControllerName eg. 'Referers'
* @param string $currentControllerAction eg. 'getKeywords'
- * @param string $moduleNameAndMethod eg. 'Referers.getKeywords'
- * @param string $actionToLoadTheSubTable eg. 'getSearchEnginesFromKeywordId'
+ * @param string $apiMethodToRequestDataTable eg. 'Referers.getKeywords'
+ * @param string $controllerActionCalledWhenRequestSubTable eg. 'getSearchEnginesFromKeywordId'
* @return void
*/
public function init( $currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod,
- $actionToLoadTheSubTable = null)
+ $apiMethodToRequestDataTable,
+ $controllerActionCalledWhenRequestSubTable = null)
{
$this->currentControllerName = $currentControllerName;
$this->currentControllerAction = $currentControllerAction;
- $this->moduleNameAndMethod = $moduleNameAndMethod;
- $this->actionToLoadTheSubTable = $actionToLoadTheSubTable;
- $this->method = $moduleNameAndMethod;
+ $this->apiMethodToRequestDataTable = $apiMethodToRequestDataTable;
+ $this->controllerActionCalledWhenRequestSubTable = $controllerActionCalledWhenRequestSubTable;
$this->idSubtable = Piwik_Common::getRequestVar('idSubtable', false, 'int');
+ $this->viewProperties['show_goals'] = false;
$this->viewProperties['show_search'] = Piwik_Common::getRequestVar('show_search', true);
$this->viewProperties['show_table_all_columns'] = Piwik_Common::getRequestVar('show_table_all_columns', true);
$this->viewProperties['show_exclude_low_population'] = Piwik_Common::getRequestVar('show_exclude_low_population', true);
$this->viewProperties['show_offset_information'] = Piwik_Common::getRequestVar('show_offset_information', true);;
$this->viewProperties['show_footer'] = Piwik_Common::getRequestVar('show_footer', true);
$this->viewProperties['show_footer_icons'] = ($this->idSubtable == false);
+ $this->viewProperties['apiMethodToRequestDataTable'] = $this->apiMethodToRequestDataTable;
+ $this->viewProperties['uniqueId'] = $this->getUniqueIdViewDataTable();
}
+
/**
* Forces the View to use a given template.
* Usually the template to use is set in the specific ViewDataTable_*
@@ -274,6 +282,26 @@ abstract class Piwik_ViewDataTable
return $this->view;
}
+ public function getCurrentControllerAction()
+ {
+ return $this->currentControllerAction;
+ }
+
+ public function getCurrentControllerName()
+ {
+ return $this->currentControllerName;
+ }
+
+ public function getApiMethodToRequestDataTable()
+ {
+ return $this->apiMethodToRequestDataTable;
+ }
+
+ public function getControllerActionCalledWhenRequestSubTable()
+ {
+ return $this->controllerActionCalledWhenRequestSubTable;
+ }
+
/**
* Returns the DataTable loaded from the API
*
@@ -299,7 +327,7 @@ abstract class Piwik_ViewDataTable
protected function loadDataTableFromAPI()
{
// we build the request string (URL) to call the API
- $requestString = $this->getRequestString();
+ $requestString = $this->getRequestString();
// we make the request to the API
$request = new Piwik_API_Request($requestString);
@@ -319,7 +347,7 @@ abstract class Piwik_ViewDataTable
// we setup the method and format variable
// - we request the method to call to get this specific DataTable
// - the format = original specifies that we want to get the original DataTable structure itself, not rendered
- $requestString = 'method='.$this->moduleNameAndMethod;
+ $requestString = 'method='.$this->apiMethodToRequestDataTable;
$requestString .= '&format=original';
$toSetEventually = array(
@@ -384,7 +412,7 @@ abstract class Piwik_ViewDataTable
* @see datatable.js
* @return string
*/
- protected function getUniqIdTable()
+ protected function getUniqueIdViewDataTable()
{
// if we request a subDataTable the $this->currentControllerAction DIV ID is already there in the page
// we make the DIV ID really unique by appending the ID of the subtable requested
@@ -477,13 +505,25 @@ abstract class Piwik_ViewDataTable
$javascriptVariablesToSet[$name] = $value;
}
}
-
+
+ if($this->dataTable instanceof Piwik_DataTable)
+ {
+ // we override the filter_sort_column with the column used for sorting,
+ // which can be different from the one specified (eg. if the column doesn't exist)
+ $javascriptVariablesToSet['filter_sort_column'] = $this->dataTable->getSortedByColumnName();
+ // datatable can return "2" but we want to write "nb_visits" in the js
+ if(isset(Piwik_Archive::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']]))
+ {
+ $javascriptVariablesToSet['filter_sort_column'] = Piwik_Archive::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']];
+ }
+ }
+
$javascriptVariablesToSet['module'] = $this->currentControllerName;
$javascriptVariablesToSet['action'] = $this->currentControllerAction;
$javascriptVariablesToSet['viewDataTable'] = $this->getViewDataTableId();
- if(!is_null($this->actionToLoadTheSubTable))
+ if(!is_null($this->controllerActionCalledWhenRequestSubTable))
{
- $javascriptVariablesToSet['actionToLoadTheSubTable'] = $this->actionToLoadTheSubTable;
+ $javascriptVariablesToSet['controllerActionCalledWhenRequestSubTable'] = $this->controllerActionCalledWhenRequestSubTable;
}
if($this->dataTable)
@@ -496,16 +536,27 @@ abstract class Piwik_ViewDataTable
// are loaded with Piwik_Common::getRequestVar()
foreach($javascriptVariablesToSet as &$value)
{
- if(is_array($value))
- {
- $value = array_map('addslashes',$value);
- }
- else
- {
+ if(is_array($value))
+ {
+ $value = array_map('addslashes',$value);
+ }
+ else
+ {
$value = addslashes($value);
}
- }
+ }
+ $deleteFromJavascriptVariables = array(
+ 'filter_excludelowpop',
+ 'filter_excludelowpop_value',
+ );
+ foreach($deleteFromJavascriptVariables as $name)
+ {
+ if(isset($javascriptVariablesToSet[$name]))
+ {
+ unset($javascriptVariablesToSet[$name]);
+ }
+ }
return $javascriptVariablesToSet;
}
@@ -605,18 +656,27 @@ abstract class Piwik_ViewDataTable
$this->viewProperties['show_table_all_columns'] = false;
}
- /**
- * Sets the pattern to look for in the table (only rows with column equal to the pattern will be kept)
- *
- * @param array $pattern arrays of patterns to look for
- * @param string $column to compare the pattern to
- * @return void
- */
- public function setExactPattern($pattern, $column)
- {
- $this->variablesDefault['filter_exact_pattern'] = $pattern;
- $this->variablesDefault['filter_exact_column'] = $column;
- }
+ /**
+ * Whether or not to show the "goal" icon
+ * @return void
+ */
+ public function enableShowGoals()
+ {
+ $this->viewProperties['show_goals'] = true;
+ }
+
+ /**
+ * Sets the pattern to look for in the table (only rows with column equal to the pattern will be kept)
+ *
+ * @param array $pattern arrays of patterns to look for
+ * @param string $column to compare the pattern to
+ * @return void
+ */
+ public function setExactPattern($pattern, $column)
+ {
+ $this->variablesDefault['filter_exact_pattern'] = $pattern;
+ $this->variablesDefault['filter_exact_column'] = $column;
+ }
/**
* Sets the value to use for the Exclude low population filter.
@@ -625,18 +685,12 @@ abstract class Piwik_ViewDataTable
* @param string The name of the column for which we compare the value to $minValue
* @return void
*/
- public function setExcludeLowPopulation( $minValue = null, $columnName = null )
+ public function setExcludeLowPopulation( $columnName = null, $minValue = null )
{
- if( is_null( $minValue) )
- {
- throw new Exception("setExcludeLowPopulation() value shouldn't be null");
- }
-
if(is_null($columnName))
{
$columnName = Piwik_Archive::INDEX_NB_VISITS;
}
-
$this->variablesDefault['filter_excludelowpop'] = $columnName;
$this->variablesDefault['filter_excludelowpop_value'] = $minValue;
}
diff --git a/core/ViewDataTable/Cloud.php b/core/ViewDataTable/Cloud.php
index 179c8959d2..29cb676eab 100644
--- a/core/ViewDataTable/Cloud.php
+++ b/core/ViewDataTable/Cloud.php
@@ -33,11 +33,11 @@ class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable
*/
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod )
+ $apiMethodToRequestDataTable )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod );
+ $apiMethodToRequestDataTable );
$this->dataTableTemplate = 'CoreHome/templates/cloud.tpl';
$this->disableOffsetInformation();
$this->disableExcludeLowPopulation();
@@ -99,8 +99,6 @@ class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable
$view->labelMetadata = $labelMetadata;
$view->cloudValues = $cloudValues;
- $view->method = $this->method;
- $view->id = $this->getUniqIdTable();
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
return $view;
diff --git a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php
index 93c69b2a49..8b51c394d6 100644
--- a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php
+++ b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php
@@ -19,198 +19,198 @@ class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDat
$this->view = new Piwik_Visualization_ChartEvolution;
}
- var $lineLabels = array();
- var $data = array();
-
- private function generateLine( $dataArray, $columns, $schema = "##label## ##column##" )
- {
- $data = array();
-
- foreach($dataArray as $keyName => $table)
- {
- $table->applyQueuedFilters();
-
- // initialize data (default values for all lines is 0)
- $dataRow = array();
-
- $rows = $table->getRows();
-
- foreach($rows as $row)
+ var $lineLabels = array();
+ var $data = array();
+
+ private function generateLine( $dataArray, $columns, $schema = "##label## ##column##" )
+ {
+ $data = array();
+
+ foreach($dataArray as $keyName => $table)
+ {
+ $table->applyQueuedFilters();
+
+ // initialize data (default values for all lines is 0)
+ $dataRow = array();
+
+ $rows = $table->getRows();
+
+ foreach($rows as $row)
+ {
+ $rowLabel = $schema;
+
+ if( strpos($rowLabel, "##label##") !== false )
+ {
+ $rowLabel = str_replace("##label##", $row->getColumn('label'), $rowLabel);
+ }
+
+ foreach($columns as $col)
+ {
+ $label = $rowLabel;
+
+ if( strpos($label, "##column##") !== false )
+ {
+ $label = str_replace("##column##", $col, $label);
+ }
+
+ if( !isset($this->lineLabels[$label]) )
+ {
+ $this->lineLabels[$label] = count($this->lineLabels);
+ }
+ $lineNb = $this->lineLabels[$label];
+
+ $value = $row->getColumn($col);
+
+ $dataRow['value'.$lineNb] = $value;
+ }
+ }
+ $data[] = $dataRow;
+ }
+ return $data;
+ }
+
+ private function generateLabels( $dataArray )
+ {
+ $data = array();
+
+ foreach($dataArray as $keyName => $table)
+ {
+ $table->applyQueuedFilters();
+
+ $data[] = array('label' => $keyName);
+ }
+
+ return $data;
+ }
+
+ private function addArray( &$data, $newData )
+ {
+ for($i = 0; $i < count($newData); $i++)
+ {
+ foreach($newData[$i] as $key => $value)
+ {
+ $data[$i][$key] = $value;
+ }
+ }
+ }
+
+ private function fillValues( &$data )
+ {
+ $nbLines = count($this->lineLabels);
+
+ for($i = 0; $i < count($data); $i++)
+ {
+ for($j = 0; $j < $nbLines; $j++)
+ {
+ if( !isset($data[$i]['value'.$j]) )
+ {
+ $data[$i]['value'.$j] = 0;
+ }
+ }
+ }
+ }
+
+ /*
+ * generates data for evolution graph from a numeric DataTable (DataTable that has only 'label' and 'value' columns)
+ */
+ protected function generateDataFromNumericDataTable($dataArray, $siteLabel = "")
+ {
+ $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
+
+ // for numeric we want to have only one column name
+ if( count($columnsToDisplay) != 1 )
+ {
+ $columnsToDisplay = array( 'nb_uniq_visitors' );
+ }
+
+ $label = $siteLabel . array_shift($columnsToDisplay);
+
+ $this->addArray($this->data, $this->generateLabels($dataArray));
+ $this->addArray($this->data, $this->generateLine($dataArray,array('value'),$label));
+ $this->fillValues($this->data);
+ }
+
+ /*
+ * generates data for evolution graph from a DataTable that has named columns (i.e. 'nb_hits', 'nb_uniq_visitors')
+ */
+ protected function generateDataFromRegularDataTable($dataArray, $siteLabel = "")
+ {
+ // get list of columns to display i.e. array('nb_hits','nb_uniq_visitors')
+ $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
+
+ // default column
+ if( count($columnsToDisplay) == 0 )
+ {
+ $columnsToDisplay = array( 'nb_uniq_visitors' );
+ }
+
+ $this->addArray($this->data, $this->generateLabels($dataArray));
+ $this->addArray($this->data, $this->generateLine($dataArray, $columnsToDisplay, $siteLabel."##label## ##column##"));
+ $this->fillValues($this->data);
+ }
+
+ protected function handleSiteGenerateDataFromDataTable($dataArray, $siteLabel = "")
+ {
+ // detect if we got numeric Datatable or regular DataTable
+ foreach($dataArray as $table)
+ {
+ $row = $table->getFirstRow();
+
+ if( $row != null )
+ {
+ $columns = $row->getColumns();
+
+ // if we got 2 columns - 'label' and 'value' this is numeric DataTable
+ if( count($columns) == 2 && isset($columns['label']) && isset($columns['value']) )
+ {
+ $this->generateDataFromNumericDataTable($dataArray, $siteLabel);
+ }
+ else
+ {
+ $this->generateDataFromRegularDataTable($dataArray, $siteLabel);
+ }
+ break;
+ }
+ }
+ }
+
+ public function generateDataFromDataTable()
+ {
+ $data = array();
+
+ if( $this->dataTable->getRowsCount() )
+ {
+ $row = null;
+
+ // find first table with rows
+ foreach($this->dataTable->getArray() as $idsite => $table)
{
- $rowLabel = $schema;
-
- if( strpos($rowLabel, "##label##") !== false )
- {
- $rowLabel = str_replace("##label##", $row->getColumn('label'), $rowLabel);
- }
-
- foreach($columns as $col)
- {
- $label = $rowLabel;
-
- if( strpos($label, "##column##") !== false )
- {
- $label = str_replace("##column##", $col, $label);
- }
-
- if( !isset($this->lineLabels[$label]) )
- {
- $this->lineLabels[$label] = count($this->lineLabels);
- }
- $lineNb = $this->lineLabels[$label];
-
- $value = $row->getColumn($col);
-
- $dataRow['value'.$lineNb] = $value;
- }
- }
- $data[] = $dataRow;
- }
- return $data;
- }
-
- private function generateLabels( $dataArray )
- {
- $data = array();
-
- foreach($dataArray as $keyName => $table)
- {
- $table->applyQueuedFilters();
-
- $data[] = array('label' => $keyName);
- }
-
- return $data;
- }
-
- private function addArray( &$data, $newData )
- {
- for($i = 0; $i < count($newData); $i++)
- {
- foreach($newData[$i] as $key => $value)
- {
- $data[$i][$key] = $value;
- }
- }
- }
-
- private function fillValues( &$data )
- {
- $nbLines = count($this->lineLabels);
-
- for($i = 0; $i < count($data); $i++)
- {
- for($j = 0; $j < $nbLines; $j++)
- {
- if( !isset($data[$i]['value'.$j]) )
- {
- $data[$i]['value'.$j] = 0;
- }
- }
- }
- }
-
- /*
- * generates data for evolution graph from a numeric DataTable (DataTable that has only 'label' and 'value' columns)
- */
- protected function generateDataFromNumericDataTable($dataArray, $siteLabel = "")
- {
- $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
-
- // for numeric we want to have only one column name
- if( count($columnsToDisplay) != 1 )
- {
- $columnsToDisplay = array( 'nb_uniq_visitors' );
- }
-
- $label = $siteLabel . array_shift($columnsToDisplay);
-
- $this->addArray($this->data, $this->generateLabels($dataArray));
- $this->addArray($this->data, $this->generateLine($dataArray,array('value'),$label));
- $this->fillValues($this->data);
- }
-
- /*
- * generates data for evolution graph from a DataTable that has named columns (i.e. 'nb_hits', 'nb_uniq_visitors')
- */
- protected function generateDataFromRegularDataTable($dataArray, $siteLabel = "")
- {
- // get list of columns to display i.e. array('nb_hits','nb_uniq_visitors')
- $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
-
- // default column
- if( count($columnsToDisplay) == 0 )
- {
- $columnsToDisplay = array( 'nb_uniq_visitors' );
- }
-
- $this->addArray($this->data, $this->generateLabels($dataArray));
- $this->addArray($this->data, $this->generateLine($dataArray, $columnsToDisplay, $siteLabel."##label## ##column##"));
- $this->fillValues($this->data);
- }
-
- protected function handleSiteGenerateDataFromDataTable($dataArray, $siteLabel = "")
- {
- // detect if we got numeric Datatable or regular DataTable
- foreach($dataArray as $table)
- {
- $row = $table->getFirstRow();
-
- if( $row != null )
- {
- $columns = $row->getColumns();
-
- // if we got 2 columns - 'label' and 'value' this is numeric DataTable
- if( count($columns) == 2 && isset($columns['label']) && isset($columns['value']) )
- {
- $this->generateDataFromNumericDataTable($dataArray, $siteLabel);
- }
- else
- {
- $this->generateDataFromRegularDataTable($dataArray, $siteLabel);
- }
- break;
- }
- }
- }
-
- public function generateDataFromDataTable()
- {
- $data = array();
-
- if( $this->dataTable->getRowsCount() )
- {
- $row = null;
-
- // find first table with rows
- foreach($this->dataTable->getArray() as $idsite => $table)
- {
- // detect if we got data from more than one site
- if( $table instanceof Piwik_DataTable_Array)
- {
- // multiple sites
- $site = new Piwik_Site($idsite);
-
- $this->handleSiteGenerateDataFromDataTable($table->getArray(), $site->getName()." ");
- }
- else if( $table instanceof Piwik_DataTable_Simple && $this->dataTable->getKeyName() == 'idSite')
- {
- // multiple sites (when numeric DataTable)
- $site = new Piwik_Site($idsite);
-
- $this->handleSiteGenerateDataFromDataTable($table->getFirstRow()->getColumn('value')->getArray(), $site->getName()." ");
- }
- else
- {
- // single site
- $this->handleSiteGenerateDataFromDataTable($this->dataTable->getArray());
- break;
- }
- }
-
- }
- array_unshift($this->data, array_keys($this->lineLabels));
-
- return $this->data;
+ // detect if we got data from more than one site
+ if( $table instanceof Piwik_DataTable_Array)
+ {
+ // multiple sites
+ $site = new Piwik_Site($idsite);
+
+ $this->handleSiteGenerateDataFromDataTable($table->getArray(), $site->getName()." ");
+ }
+ else if( $table instanceof Piwik_DataTable_Simple && $this->dataTable->getKeyName() == 'idSite')
+ {
+ // multiple sites (when numeric DataTable)
+ $site = new Piwik_Site($idsite);
+
+ $this->handleSiteGenerateDataFromDataTable($table->getFirstRow()->getColumn('value')->getArray(), $site->getName()." ");
+ }
+ else
+ {
+ // single site
+ $this->handleSiteGenerateDataFromDataTable($this->dataTable->getArray());
+ break;
+ }
+ }
+
+ }
+ array_unshift($this->data, array_keys($this->lineLabels));
+
+ return $this->data;
}
}
diff --git a/core/ViewDataTable/GenerateGraphHTML.php b/core/ViewDataTable/GenerateGraphHTML.php
index 3204361748..58849049d3 100644
--- a/core/ViewDataTable/GenerateGraphHTML.php
+++ b/core/ViewDataTable/GenerateGraphHTML.php
@@ -27,11 +27,11 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
*/
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod )
+ $apiMethodToRequestDataTable )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod );
+ $apiMethodToRequestDataTable );
$this->dataTableTemplate = 'CoreHome/templates/graph.tpl';
@@ -74,7 +74,7 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
protected function buildView()
{
$view = new Piwik_View($this->dataTableTemplate);
- $this->id = $this->getUniqIdTable();
+ $this->uniqueIdViewDataTable = $this->getUniqueIdViewDataTable();
$view->graphType = $this->graphType;
$this->parametersToModify['action'] = $this->currentControllerAction;
@@ -82,11 +82,9 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
$view->jsInvocationTag = $this->getFlashInvocationCode($url);
$view->urlGraphData = $url;
- $view->formEmbedId = "formEmbed".$this->id;
+ $view->formEmbedId = "formEmbed".$this->uniqueIdViewDataTable;
$view->graphCodeEmbed = $this->graphCodeEmbed;
- $view->id = $this->id;
- $view->method = $this->method;
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
return $view;
@@ -105,8 +103,8 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
// escape the & and stuff:
$url = urlencode($url);
- $obj_id = $this->id . "Chart";
- $div_name = $this->id . "FlashContent";
+ $obj_id = $this->uniqueIdViewDataTable . "Chart";
+ $div_name = $this->uniqueIdViewDataTable . "FlashContent";
$return = '';
if( $use_swfobject )
diff --git a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php b/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php
index 0eb29034e3..98fa9323a8 100644
--- a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php
+++ b/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php
@@ -28,24 +28,24 @@ class Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution extends Piwik_ViewDat
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod )
+ $apiMethodToRequestDataTable )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod );
+ $apiMethodToRequestDataTable );
$this->setParametersToModify(array('date' => Piwik_Common::getRequestVar('date', 'last30', 'string')));
$this->doNotShowFooter();
}
-
- /**
- * Sets the columns that will be displayed on output evolution chart
- * By default all columns are displayed ($columnsNames = array() will display all columns)
- *
- * @param array $columnsNames Array of column names eg. array('nb_visits','nb_hits')
- */
- public function setColumnsToDisplay( $columnsNames)
- {
- $this->setParametersToModify( array('columns' => $columnsNames) );
- }
+
+ /**
+ * Sets the columns that will be displayed on output evolution chart
+ * By default all columns are displayed ($columnsNames = array() will display all columns)
+ *
+ * @param array $columnsNames Array of column names eg. array('nb_visits','nb_hits')
+ */
+ public function setColumnsToDisplay( $columnsNames)
+ {
+ $this->setParametersToModify( array('columns' => $columnsNames) );
+ }
} \ No newline at end of file
diff --git a/core/ViewDataTable/HtmlTable.php b/core/ViewDataTable/HtmlTable.php
index 9c27447417..3beb82265e 100644
--- a/core/ViewDataTable/HtmlTable.php
+++ b/core/ViewDataTable/HtmlTable.php
@@ -53,21 +53,15 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
*/
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod,
- $actionToLoadTheSubTable = null )
+ $apiMethodToRequestDataTable,
+ $controllerActionCalledWhenRequestSubTable = null )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod,
- $actionToLoadTheSubTable);
+ $apiMethodToRequestDataTable,
+ $controllerActionCalledWhenRequestSubTable);
$this->dataTableTemplate = 'CoreHome/templates/datatable.tpl';
-
$this->variablesDefault['enable_sort'] = '1';
-
- // load general columns translations
- $this->setColumnTranslation('nb_visits', Piwik_Translate('General_ColumnNbVisits'));
- $this->setColumnTranslation('label', Piwik_Translate('General_ColumnLabel'));
- $this->setColumnTranslation('nb_uniq_visitors', Piwik_Translate('General_ColumnNbUniqVisitors'));
}
protected function getViewDataTableId()
@@ -97,6 +91,10 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
*/
protected function postDataTableLoadedFromAPI()
{
+ // load general columns translations
+ $this->setColumnTranslation('nb_visits', Piwik_Translate('General_ColumnNbVisits'));
+ $this->setColumnTranslation('label', Piwik_Translate('General_ColumnLabel'));
+ $this->setColumnTranslation('nb_uniq_visitors', Piwik_Translate('General_ColumnNbUniqVisitors'));
}
/**
@@ -109,7 +107,6 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
$phpArray = $this->getPHPArrayFromDataTable();
$view->arrayDataTable = $phpArray;
- $view->method = $this->method;
$columns = $this->getColumnsToDisplay($phpArray);
$view->dataTableColumns = $columns;
@@ -122,11 +119,24 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
}
$view->nbColumns = $nbColumns;
- $view->id = $this->getUniqIdTable();
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
return $view;
}
+
+ protected function handleLowPopulation( $columnToApplyFilter = null)
+ {
+ if(Piwik_Common::getRequestVar('enable_filter_excludelowpop', '0', 'string' ) == '0')
+ {
+ return;
+ }
+
+ if(is_null($columnToApplyFilter))
+ {
+ $columnToApplyFilter = Piwik_Archive::INDEX_NB_VISITS;
+ }
+ $this->setExcludeLowPopulation( $columnToApplyFilter);
+ }
/**
* Returns friendly php array from the Piwik_DataTable
@@ -156,6 +166,16 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
}
/**
+ * Adds a column to the list of columns to be displayed
+ *
+ * @param string $columnName
+ */
+ public function addColumnToDisplay( $columnName )
+ {
+ $this->columnsToDisplay[] = $columnName;
+ }
+
+ /**
* Sets translation string for given column
*
* @param string $columnName column name
@@ -217,6 +237,7 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
$columnsToDisplay = $columnsInDataTable;
}
+ $columnsToDisplay = array_unique($columnsToDisplay);
foreach($columnsToDisplay as $columnToDisplay)
{
if(in_array($columnToDisplay, $columnsInDataTable))
diff --git a/core/ViewDataTable/HtmlTable/AllColumns.php b/core/ViewDataTable/HtmlTable/AllColumns.php
index 9ea33f5a85..e1c0882301 100644
--- a/core/ViewDataTable/HtmlTable/AllColumns.php
+++ b/core/ViewDataTable/HtmlTable/AllColumns.php
@@ -3,8 +3,6 @@ require_once "ViewDataTable/HtmlTable.php";
class Piwik_ViewDataTable_HtmlTable_AllColumns extends Piwik_ViewDataTable_HtmlTable
{
- const LOW_POPULATION_THRESHOLD_PERCENTAGE_VISIT = 0.005;
-
protected function getViewDataTableId()
{
return 'tableAllColumns';
@@ -18,22 +16,6 @@ class Piwik_ViewDataTable_HtmlTable_AllColumns extends Piwik_ViewDataTable_HtmlT
parent::main();
}
- protected function handleLowPopulation()
- {
- if(Piwik_Common::getRequestVar('filter_excludelowpop', '0', 'string' ) == '0')
- {
- return;
- }
-
- require_once "VisitsSummary/Controller.php";
- $visits = Piwik_VisitsSummary_Controller::getVisits();
- $visitsThreshold = floor( self::LOW_POPULATION_THRESHOLD_PERCENTAGE_VISIT * $visits);
- if($visitsThreshold > 0)
- {
- $this->setExcludeLowPopulation( $visitsThreshold, Piwik_Archive::INDEX_NB_VISITS );
- }
- }
-
protected function getRequestString()
{
$requestString = parent::getRequestString();
@@ -42,6 +24,7 @@ class Piwik_ViewDataTable_HtmlTable_AllColumns extends Piwik_ViewDataTable_HtmlT
protected function postDataTableLoadedFromAPI()
{
+ parent::postDataTableLoadedFromAPI();
$this->setColumnsToDisplay(array('label',
'nb_visits',
'nb_uniq_visitors',
diff --git a/core/ViewDataTable/HtmlTable/Goals.php b/core/ViewDataTable/HtmlTable/Goals.php
new file mode 100644
index 0000000000..ebb5d9e800
--- /dev/null
+++ b/core/ViewDataTable/HtmlTable/Goals.php
@@ -0,0 +1,77 @@
+<?php
+require_once "ViewDataTable/HtmlTable.php";
+
+class Piwik_ViewDataTable_HtmlTable_Goals extends Piwik_ViewDataTable_HtmlTable
+{
+ protected function getViewDataTableId()
+ {
+ return 'tableGoals';
+ }
+
+ public function main()
+ {
+ $this->viewProperties['show_exclude_low_population'] = true;
+ $this->viewProperties['show_goals'] = true;
+ $this->setColumnsToDisplay( array( 'label',
+ 'nb_visits',
+ 'goals_conversion_rate',
+ 'goal_%s_conversion_rate',
+ 'revenue_per_visit',
+ ));
+ $this->handleLowPopulation();
+ parent::main();
+ }
+
+ public function disableSubTableWhenShowGoals()
+ {
+ $this->controllerActionCalledWhenRequestSubTable = null;
+ }
+
+ protected function getRequestString()
+ {
+ $requestString = parent::getRequestString();
+ return $requestString . '&filter_update_columns_when_show_all_goals=1';
+ }
+
+ protected $columnsToPercentageFilter = array();
+
+ public function setColumnsToDisplay($columnsNames)
+ {
+ $newColumnsNames = array();
+ foreach($columnsNames as $columnName)
+ {
+ if($columnName == 'goal_%s_conversion_rate')
+ {
+ require_once "core/Tracker/GoalManager.php";
+ $goals = Piwik_Tracker_GoalManager::getGoalDefinitions();
+ foreach($goals as $goal)
+ {
+ $idgoal = $goal['id'];
+ $name = $goal['name'];
+ $columnName = 'goal_'.$idgoal.'_conversion_rate';
+ $newColumnsNames[] = $columnName;
+ $this->setColumnTranslation($columnName, $name);
+ $this->columnsToPercentageFilter[] = $columnName;
+ }
+ }
+ else
+ {
+ $newColumnsNames[] = $columnName;
+ }
+ }
+ parent::setColumnsToDisplay($newColumnsNames);
+ }
+
+ protected function postDataTableLoadedFromAPI()
+ {
+ parent::postDataTableLoadedFromAPI();
+ $this->setColumnTranslation('revenue_per_visit', 'Value per Visit');
+ $this->setColumnTranslation('goals_conversion_rate', 'Visits with Conversions');
+ $this->columnsToPercentageFilter[] = 'goals_conversion_rate';
+ foreach($this->columnsToPercentageFilter as $columnName)
+ {
+ $filter = new Piwik_DataTable_Filter_ColumnCallbackReplace($this->dataTable, $columnName, create_function('$rate', 'return $rate."%";'));
+ }
+ $filter = new Piwik_DataTable_Filter_ColumnCallbackReplace($this->dataTable, 'revenue_per_visit', array("Piwik", "getPrettyMoney"));
+ }
+}
diff --git a/core/ViewDataTable/Sparkline.php b/core/ViewDataTable/Sparkline.php
index ab6fce4ce7..f9908a50fa 100644
--- a/core/ViewDataTable/Sparkline.php
+++ b/core/ViewDataTable/Sparkline.php
@@ -24,18 +24,6 @@ class Piwik_ViewDataTable_Sparkline extends Piwik_ViewDataTable
}
/**
- * @see Piwik_ViewDataTable::init()
- */
- function init($currentControllerName,
- $currentControllerAction,
- $moduleNameAndMethod )
- {
- parent::init($currentControllerName,
- $currentControllerAction,
- $moduleNameAndMethod );
- }
-
- /**
* @see Piwik_ViewDataTable::main()
*/
public function main()
@@ -64,6 +52,15 @@ class Piwik_ViewDataTable_Sparkline extends Piwik_ViewDataTable
}
/**
+ * Sparkline needs to be fast to load. Currently we only load numeric values
+ * that do not need filtering, we can disable the filters for more performance.
+ */
+ protected function getRequestString()
+ {
+ return parent::getRequestString() . "&disable_generic_filters=1";
+ }
+
+ /**
* Given a Piwik_DataTable_Array made of DataTable_Simple rows, returns a php array with the structure:
* array(
* array( label => X, value => Y),
diff --git a/core/Visualization/ChartEvolution.php b/core/Visualization/ChartEvolution.php
index 9160eb8bc2..82f2da4fa4 100644
--- a/core/Visualization/ChartEvolution.php
+++ b/core/Visualization/ChartEvolution.php
@@ -1,72 +1,72 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: ChartVerticalBar.php 168 2008-01-14 05:26:43Z matt $
- *
- * @package Piwik_Visualization
- */
-
-require_once "Visualization/Chart.php";
-
-/**
- * Customize the Evolution chart style for the flash graph
- *
- * @package Piwik_Visualization
- */
-class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
-{
- function customizeGraph()
- {
- parent::customizeGraph();
- //$this->prepareData();
-
- $colors = array(
- "0x3357A0",
- "0x9933CC",
- "0xCC3399",
- "0x80a033",
- "0xFD9816",
- "0x246AD2",
- "0xFD16EA",
- "0x49C100",
- );
-
- // first row in array contains line labels (legend)
- $legendLabels = array_shift($this->dataGraph);
-
- $line = array();
-
- // define labels
- foreach($legendLabels as $nbLabel => $labelName)
- {
- $line[$nbLabel] = new line_hollow( 1, 3, $colors[$nbLabel] );
- $line[$nbLabel]->key( $labelName, 10 );
- }
-
- $maxData = 0;
- $xLabels = array();
- $cnt = count($this->dataGraph);
-
- // loop over data
- foreach($this->dataGraph as $values)
- {
- // add x axis value (label)
- array_push($xLabels, $values['label']);
-
- // loop over values for all lines (y axis values)
- for($j = 0; $j < count($legendLabels); $j++)
- {
- // get the y axis value for line $j
- $dotValue = $values['value'.$j];
-
- // find maximum y axis value
- if( $dotValue > $maxData )
- {
- $maxData = $dotValue;
- }
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: ChartVerticalBar.php 168 2008-01-14 05:26:43Z matt $
+ *
+ * @package Piwik_Visualization
+ */
+
+require_once "Visualization/Chart.php";
+
+/**
+ * Customize the Evolution chart style for the flash graph
+ *
+ * @package Piwik_Visualization
+ */
+class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
+{
+ function customizeGraph()
+ {
+ parent::customizeGraph();
+ //$this->prepareData();
+
+ $colors = array(
+ "0x3357A0",
+ "0x9933CC",
+ "0xCC3399",
+ "0x80a033",
+ "0xFD9816",
+ "0x246AD2",
+ "0xFD16EA",
+ "0x49C100",
+ );
+
+ // first row in array contains line labels (legend)
+ $legendLabels = array_shift($this->dataGraph);
+
+ $line = array();
+
+ // define labels
+ foreach($legendLabels as $nbLabel => $labelName)
+ {
+ $line[$nbLabel] = new line_hollow( 1, 3, $colors[$nbLabel] );
+ $line[$nbLabel]->key( $labelName, 10 );
+ }
+
+ $maxData = 0;
+ $xLabels = array();
+ $cnt = count($this->dataGraph);
+
+ // loop over data
+ foreach($this->dataGraph as $values)
+ {
+ // add x axis value (label)
+ array_push($xLabels, $values['label']);
+
+ // loop over values for all lines (y axis values)
+ for($j = 0; $j < count($legendLabels); $j++)
+ {
+ // get the y axis value for line $j
+ $dotValue = $values['value'.$j];
+
+ // find maximum y axis value
+ if( $dotValue > $maxData )
+ {
+ $maxData = $dotValue;
+ }
$link = null;
if($this->isLinkEnabled())
@@ -89,12 +89,12 @@ class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
else
{
$line[$j]->add($dotValue);
- }
- }
- }
- $this->data_sets = $line;
- $this->set_y_max( $maxData );
- $this->set_x_labels( $xLabels );
+ }
+ }
+ }
+ $this->data_sets = $line;
+ $this->set_y_max( $maxData );
+ $this->set_x_labels( $xLabels );
}
private function isLinkEnabled()
@@ -105,5 +105,5 @@ class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
$linkEnabled = !Piwik_Common::getRequestVar('disableLink', 0, 'int');
}
return $linkEnabled;
- }
+ }
}
diff --git a/misc/TODO b/misc/TODO
index e52dab9f68..bd1fc45730 100644
--- a/misc/TODO
+++ b/misc/TODO
@@ -3,18 +3,21 @@ Following up show all columns new UI element
- passe en année, actions puis pages => c'est vide !!!
- pages columns: first should be unique page views, sorted by unique pageviews
- exclude all population doesn't work for actions
+- when used with visitsGenerator, in dowloads export XML, full_url and url is 0
+- add new column "overall visits with conversion"
- post 29 There seems not to be a way to export the pages information widget. I wanted to download the entry pages to see where my visitors entered my site from, but there is no option to do so.
-
-$("td img", domElem).attr("src") is undefined
-[Break on this error] var plusDetected = $('td img', domElem).attr('src').indexOf('plus') >= 0;
-datatable.js (line 907)
-$("td img", domElem).attr("src") is undefined
-[Break on this error] var plusDetected = $('td img', domElem).attr('src').indexOf('plus') >= 0;
-when clicking MINUS on actions
+ $("td img", domElem).attr("src") is undefined
+ [Break on this error] var plusDetected = $('td img', domElem).attr('src').indexOf('plus') >= 0;
+ datatable.js (line 907)
+ $("td img", domElem).attr("src") is undefined
+ [Break on this error] var plusDetected = $('td img', domElem).attr('src').indexOf('plus') >= 0;
+ when clicking MINUS on actions
- icons disappear when showing all columns for browsers
- exclude low population doesn't work for providers
- ADD forward of non true show_values to forward when specified from URL to ajax
- disable show icon in some iframes and/or dashboard
+- when exclude low, switch back to normal table, include all is not avail and low are still excluded
+ ->when switch back to simple table, reset exclude
- do proper CSS factoring
- clarify 'false' '0' values etc. //convert all JS datatable footer parameter values to '1' or '0'
- check state of javascript footer (should not have safe_decode and filter_add_columns blah)
@@ -39,26 +42,31 @@ UI fixes + adjustements
- write test to check disabled db plugin default
- show total size in MB in db plugin
- search inside datatable doesnt really work eg. "web analytics" restore regex search
+ can we find a "binary operator string -> regex" conversion function?
- bounce count should be bounce rate
- idem in 222 times that a returning visit has bounced (left the site after one page)
- show new vs returning more clearly in UI
- calendar CSS on API page
- WRONG::: 147 sites Internet différents (utilisant 147 différentes adresses)
- see also #421
+- add "days since last visit"
+- add "visit count until conversion"
check analytics books
high priority features
====
-- tester clickheat http://www.labsmedia.com/clickheat/piwik-clickheat.tar.gz + add FAQ
-- sync update + email install
- Goal tracking
+- tester clickheat http://www.labsmedia.com/clickheat/piwik-clickheat.tar.gz + add FAQ
+- sync update + email install + automatic update
- Live!
- simple MultiSites report plugin.
- new JS tagging API
- Exclude webmaster
- Loyalty (Most people visited: 1 times) and Recency (Most people last visited: X days ago)
-
+ http://en.wikipedia.org/wiki/RFM
+
+
UI elements:
====
- add link under widgets to report (optional display)
@@ -75,9 +83,12 @@ website
Bugs
- add icon calendar http://developer.yahoo.com/ypatterns/pattern.php?pattern=calendar#Solution
- something is wrong in JS calendar when year selected
-- I had to chmod 777 tmp/ to pass install
-all graphic showing data evolution are labelled with the text &quot;nb_uniq_visitors&quot; no matter if youre watching last visits graph, global visits graph or any other. Its happening in every graph under Visitors subpages and in the Dashboard.
-In Referers-&gt;Evolution page, in addition, I think its melting titles because I read in spanish &quot;Entrada directa nb_uniq_visitors&quot; for the first graph, &quot;Paginas web nb_uniq_visitors&quot; for the second and so on.
+- all graphic showing data evolution are labelled with the text &quot;nb_uniq_visitors&quot;
+ no matter if youre watching last visits graph, global visits graph or any other.
+ Its happening in every graph under Visitors subpages and in the Dashboard.
+- In Referers-&gt;Evolution page, in addition, I think its melting titles because I read
+ in spanish &quot;Entrada directa nb_uniq_visitors&quot; for the first graph,
+ &quot;Paginas web nb_uniq_visitors&quot; for the second and so on.
To clean
- plugins should listen to user delete/ site delete and delete their own user/site related data
diff --git a/misc/generateVisits.php b/misc/generateVisits.php
index f8984199e8..38774e0d00 100644
--- a/misc/generateVisits.php
+++ b/misc/generateVisits.php
@@ -3,10 +3,10 @@
* The script can be used to generate huge number of visits and actions
* for a given number of days.
*/
-$minVisitors = 500;
-$maxVisitors = 1000;
+$minVisitors = 200;
+$maxVisitors = 200;
$nbActions = 3;
-$daysToCompute = 1;
+$daysToCompute = 10;
//-----------------------------------------------------------------------------
error_reporting(E_ALL|E_NOTICE);
@@ -46,6 +46,7 @@ require_once "Tracker/Action.php";
require_once "Tracker/Db.php";
require_once "Tracker/Visit.php";
require_once "Tracker/Generator.php";
+require_once "Tracker/GoalManager.php";
//Piwik_PluginsManager::getInstance()->unloadPlugins();
@@ -73,6 +74,7 @@ while($startTime <= time())
$visitors = rand($minVisitors, $maxVisitors);
$actions = $nbActions;
$generator->setTimestampToUse($startTime);
+
$nbActionsTotalThisDay = $generator->generate($visitors, $actions);
$actionsPerVisit = round($nbActionsTotalThisDay / $visitors);
print("Generated $visitors unique visitors and $actionsPerVisit actions per visit for the ".date("Y-m-d", $startTime)."<br>\n");
diff --git a/piwik.php b/piwik.php
index 413ef7d147..b4a8d922b5 100644
--- a/piwik.php
+++ b/piwik.php
@@ -25,6 +25,7 @@ require_once "Tracker/Action.php";
require_once "Cookie.php";
require_once "Tracker/Db.php";
require_once "Tracker/Visit.php";
+require_once "Tracker/GoalManager.php";
$GLOBALS['DEBUGPIWIK'] = false;
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index 0972d00e46..4545762f64 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -1,21 +1,21 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id$
- *
- * @package Piwik_Actions
- */
-
-/**
- *
- * @package Piwik_Actions
- */
-class Piwik_Actions extends Piwik_Plugin
-{
- static protected $actionCategoryDelimiter = null;
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_Actions
+ */
+
+/**
+ *
+ * @package Piwik_Actions
+ */
+class Piwik_Actions extends Piwik_Plugin
+{
+ static protected $actionCategoryDelimiter = null;
static protected $limitLevelSubCategory = 10;
public function getInformation()
@@ -41,309 +41,310 @@ class Piwik_Actions extends Piwik_Plugin
);
return $hooks;
}
-
- public function __construct()
+
+ public function __construct()
+ {
+ $this->setCategoryDelimiter( Zend_Registry::get('config')->General->action_category_delimiter);
+ }
+
+ public function setCategoryDelimiter($delimiter)
{
- $this->setCategoryDelimiter( Zend_Registry::get('config')->General->action_category_delimiter);
- }
-
- public function setCategoryDelimiter($delimiter)
- {
- self::$actionCategoryDelimiter = $delimiter;
- }
-
+ self::$actionCategoryDelimiter = $delimiter;
+ }
+
function addWidgets()
{
Piwik_AddWidget( 'Actions', 'getActions', Piwik_Translate('Actions_SubmenuPages'));
Piwik_AddWidget( 'Actions', 'getDownloads', Piwik_Translate('Actions_SubmenuDownloads'));
Piwik_AddWidget( 'Actions', 'getOutlinks', Piwik_Translate('Actions_SubmenuOutlinks'));
}
-
- function addMenus()
- {
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getActions'));
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks'));
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads'));
- }
-
- function archivePeriod( $notification )
- {
- $archiveProcessing = $notification->getNotificationObject();
-
- $dataTableToSum = array(
- 'Actions_actions',
- 'Actions_downloads',
- 'Actions_outlink',
- );
+
+ function addMenus()
+ {
+ Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getActions'));
+ Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks'));
+ Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads'));
+ }
+
+ function archivePeriod( $notification )
+ {
+ $archiveProcessing = $notification->getNotificationObject();
+
+ $dataTableToSum = array(
+ 'Actions_actions',
+ 'Actions_downloads',
+ 'Actions_outlink',
+ );
$maximumRowsInDataTableLevelZero = 200;
- $maximumRowsInSubDataTable = 50;
- $archiveProcessing->archiveDataTable($dataTableToSum, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- }
-
- /**
- * Compute all the actions along with their hierarchies.
- *
- * For each action we process the "interest statistics" :
- * visits, unique visitors, bouce count, sum visit length.
- *
- *
- */
- public function archiveDay( $notification )
- {
- $archiveProcessing = $notification->getNotificationObject();
-
- require_once "Tracker/Action.php";
-
- $this->actionsTablesByType = array(
- Piwik_Tracker_Action::TYPE_ACTION => array(),
- Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
- Piwik_Tracker_Action::TYPE_OUTLINK => array(),
- );
-
- // This row is used in the case where an action is know as an exit_action
- // but this action was not properly recorded when it was hit in the first place
- // so we add this fake row information to make sure there is a nb_hits, etc. column for every action
- $this->defaultRow = new Piwik_DataTable_Row(array(
- Piwik_DataTable_Row::COLUMNS => array(
- 'nb_visits' => 1,
- 'nb_uniq_visitors' => 1,
- 'nb_hits' => 1,
- )));
-
- /*
- * Actions global information
- */
- $query = "SELECT name,
- type,
- count(distinct t1.idvisit) as nb_visits,
- count(distinct visitor_idcookie) as nb_uniq_visitors,
- count(*) as nb_hits
- FROM (".$archiveProcessing->logTable." as t1
- LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit))
- LEFT JOIN ".$archiveProcessing->logActionTable." as t3 USING (idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ $maximumRowsInSubDataTable = 50;
+ $archiveProcessing->archiveDataTable($dataTableToSum, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
+ }
+
+ /**
+ * Compute all the actions along with their hierarchies.
+ *
+ * For each action we process the "interest statistics" :
+ * visits, unique visitors, bouce count, sum visit length.
+ *
+ *
+ */
+ public function archiveDay( $notification )
+ {
+ $archiveProcessing = $notification->getNotificationObject();
+
+ require_once "Tracker/Action.php";
+
+ $this->actionsTablesByType = array(
+ Piwik_Tracker_Action::TYPE_ACTION => array(),
+ Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
+ Piwik_Tracker_Action::TYPE_OUTLINK => array(),
+ );
+
+ // This row is used in the case where an action is know as an exit_action
+ // but this action was not properly recorded when it was hit in the first place
+ // so we add this fake row information to make sure there is a nb_hits, etc. column for every action
+ $this->defaultRow = new Piwik_DataTable_Row(array(
+ Piwik_DataTable_Row::COLUMNS => array(
+ 'nb_visits' => 1,
+ 'nb_uniq_visitors' => 1,
+ 'nb_hits' => 1,
+ )));
+
+ /*
+ * Actions global information
+ */
+ $query = "SELECT name,
+ type,
+ count(distinct t1.idvisit) as nb_visits,
+ count(distinct visitor_idcookie) as nb_uniq_visitors,
+ count(*) as nb_hits
+ FROM (".$archiveProcessing->logTable." as t1
+ LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit))
+ LEFT JOIN ".$archiveProcessing->logActionTable." as t3 USING (idaction)
+ WHERE visit_server_date = ?
+ AND idsite = ?
GROUP BY t3.idaction
- ORDER BY nb_hits DESC";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
-
- /*
- * Entry actions
- */
- $query = "SELECT name,
- type,
- count(distinct visitor_idcookie) as entry_nb_unique_visitor,
- count(*) as entry_nb_visits,
- sum(visit_total_actions) as entry_nb_actions,
- sum(visit_total_time) as entry_sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count
- FROM ".$archiveProcessing->logTable."
- JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction = idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ ORDER BY nb_hits DESC";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
+
+
+ /*
+ * Entry actions
+ */
+ $query = "SELECT name,
+ type,
+ count(distinct visitor_idcookie) as entry_nb_unique_visitor,
+ count(*) as entry_nb_visits,
+ sum(visit_total_actions) as entry_nb_actions,
+ sum(visit_total_time) as entry_sum_visit_length,
+ sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count
+ FROM ".$archiveProcessing->logTable."
+ JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction = idaction)
+ WHERE visit_server_date = ?
+ AND idsite = ?
GROUP BY visit_entry_idaction
- ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
-
- /*
- * Exit actions
- */
- $query = "SELECT name,
- type,
- count(distinct visitor_idcookie) as exit_nb_unique_visitor,
- count(*) as exit_nb_visits,
- sum(case visit_total_actions when 1 then 1 else 0 end) as exit_bounce_count
-
- FROM ".$archiveProcessing->logTable."
- JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction = idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ ";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
+
+
+ /*
+ * Exit actions
+ */
+ $query = "SELECT name,
+ type,
+ count(distinct visitor_idcookie) as exit_nb_unique_visitor,
+ count(*) as exit_nb_visits,
+ sum(case visit_total_actions when 1 then 1 else 0 end) as exit_bounce_count
+
+ FROM ".$archiveProcessing->logTable."
+ JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction = idaction)
+ WHERE visit_server_date = ?
+ AND idsite = ?
GROUP BY visit_exit_idaction
- ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
- /*
- * Time per action
- */
- $query = "SELECT name,
- type,
- sum(time_spent_ref_action) as sum_time_spent
- FROM (".$archiveProcessing->logTable." log_visit
- JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit))
- JOIN ".$archiveProcessing->logActionTable." log_action ON (log_action.idaction = log_link_visit_action.idaction_ref)
- WHERE visit_server_date = ?
- AND idsite = ?
- GROUP BY idaction_ref
- ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
+ ";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
+
+ /*
+ * Time per action
+ */
+ $query = "SELECT name,
+ type,
+ sum(time_spent_ref_action) as sum_time_spent
+ FROM (".$archiveProcessing->logTable." log_visit
+ JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit))
+ JOIN ".$archiveProcessing->logActionTable." log_action ON (log_action.idaction = log_link_visit_action.idaction_ref)
+ WHERE visit_server_date = ?
+ AND idsite = ?
+ GROUP BY idaction_ref
+ ";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
+ $this->archiveDayRecordInDatabase();
+ }
+
+ protected function archiveDayRecordInDatabase()
+ {
$maximumRowsInDataTableLevelZero = 200;
$maximumRowsInSubDataTable = 50;
$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION]);
$s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_actions', $s);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_actions', $s);
$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD]);
$s = $dataTable->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_downloads', $s);
-
- $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]);
- $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_outlink', $s);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_downloads', $s);
+
+ $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]);
+ $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_outlink', $s);
- unset($this->actionsTablesByType);
- }
-
- static public function splitUrl($url)
- {
- $matches = $split_arr = array();
- $n = preg_match("#://[^/]+(/)#",$url, $matches, PREG_OFFSET_CAPTURE);
- if( $n )
- {
- $host = substr($url, 0, $matches[1][1]);
- $split_arr = array($host, $url);
- }
- else
- {
- $split_arr = array($url);
- }
- return $split_arr;
- }
-
- static public function getActionCategoryFromName($name)
- {
- $isUrl = false;
- // case the name is an URL we dont clean the name the same way
- if(Piwik_Common::isLookLikeUrl($name)
- || preg_match('#^mailto:#',$name))
- {
- $split = self::splitUrl($name);
- $isUrl = true;
- }
- else
+ unset($this->actionsTablesByType);
+ }
+
+ static public function splitUrl($url)
+ {
+ $matches = $split_arr = array();
+ $n = preg_match("#://[^/]+(/)#",$url, $matches, PREG_OFFSET_CAPTURE);
+ if( $n )
+ {
+ $host = substr($url, 0, $matches[1][1]);
+ $split_arr = array($host, $url);
+ }
+ else
+ {
+ $split_arr = array($url);
+ }
+ return $split_arr;
+ }
+
+ static public function getActionCategoryFromName($name)
+ {
+ $isUrl = false;
+ // case the name is an URL we dont clean the name the same way
+ if(Piwik_Common::isLookLikeUrl($name)
+ || preg_match('#^mailto:#',$name))
+ {
+ $split = self::splitUrl($name);
+ $isUrl = true;
+ }
+ else
{
if(empty(self::$actionCategoryDelimiter))
{
$split = array($name);
}
else
- {
+ {
$split = explode(self::$actionCategoryDelimiter, $name, self::$limitLevelSubCategory);
- }
- }
- return array( $isUrl, $split);
- }
-
-
- protected function updateActionsTableWithRowQuery($query)
- {
- $rowsProcessed = 0;
-
- while( $row = $query->fetch() )
- {
- // split the actions by category
- $returned = $this->getActionCategoryFromName($row['name']);
- $aActions = $returned[1];
- $isUrl = $returned[0];
-
- // we work on the root table of the given TYPE (either ACTION or DOWNLOAD or OUTLINK etc.)
- $currentTable =& $this->actionsTablesByType[$row['type']];
-
- // go to the level of the subcategory
- $end = count($aActions)-1;
- for($level = 0 ; $level < $end; $level++)
- {
- $actionCategory = $aActions[$level];
- $currentTable =& $currentTable[$actionCategory];
- }
- $actionName = $aActions[$end];
-
- // create a new element in the array for the page
- // we are careful to prefix the pageName with some value so that if a page has the same name
- // as a category we don't overwrite or do other silly things
-
- // if the page name is not a URL we add a / before
- if( !$isUrl )
- {
- // we know that the concatenation of a space and the name of the action
- // will always be unique as all the action names have been trimmed before reaching this point
- $actionName = '/' . $actionName;
- }
- else
- {
- $actionName = ' ' . $actionName;
- }
-
- // currentTable is now the array element corresponding the the action
- // at this point we may be for example at the 4th level of depth in the hierarchy
- $currentTable =& $currentTable[$actionName];
-
- // add the row to the matching sub category subtable
- if(!($currentTable instanceof Piwik_DataTable_Row))
- {
- $currentTable = new Piwik_DataTable_Row(
- array( Piwik_DataTable_Row::COLUMNS =>
- array( 'label' => (string)$actionName,
- 'full_url' => (string)$row['name'],
- )
- )
- );
- }
-
- foreach($row as $name => $value)
- {
- // we don't add this information as itnot pertinent
- // name is already set as the label // and it has been cleaned from the categories and extracted from the initial string
- // type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate.
- if($name != 'name' && $name != 'type')
- {
- // in some very rare case, we actually have twice the same action name with 2 different idaction
- // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page,
- // and in between the two the other visitor comes.
- // here we handle the case where there is already a row for this action name, if this is the case we add the value
- if(($alreadyValue = $currentTable->getColumn($name)) !== false)
- {
- $currentTable->setColumn($name, $alreadyValue+$value);
- }
- else
- {
- $currentTable->addColumn($name, $value);
- }
- }
- }
-
- // if the exit_action was not recorded properly in the log_link_visit_action
- // there would be an error message when getting the nb_hits column
- // we must fake the record and add the columns
- if($currentTable->getColumn('nb_hits') === false)
- {
- // to test this code: delete the entries in log_link_action_visit for
- // a given exit_idaction
- foreach($this->defaultRow->getColumns() as $name => $value)
- {
- $currentTable->addColumn($name, $value);
- }
- }
- // simple count
- $rowsProcessed++;
- }
-
- // just to make sure php copies the last $currentTable in the $parentTable array
- $currentTable =& $this->actionsTablesByType;
-
- return $rowsProcessed;
- }
-}
-
+ }
+ }
+ return array( $isUrl, $split);
+ }
+
+
+ protected function updateActionsTableWithRowQuery($query)
+ {
+ $rowsProcessed = 0;
+
+ while( $row = $query->fetch() )
+ {
+ // split the actions by category
+ $returned = $this->getActionCategoryFromName($row['name']);
+ $aActions = $returned[1];
+ $isUrl = $returned[0];
+
+ // we work on the root table of the given TYPE (either ACTION or DOWNLOAD or OUTLINK etc.)
+ $currentTable =& $this->actionsTablesByType[$row['type']];
+
+ // go to the level of the subcategory
+ $end = count($aActions)-1;
+ for($level = 0 ; $level < $end; $level++)
+ {
+ $actionCategory = $aActions[$level];
+ $currentTable =& $currentTable[$actionCategory];
+ }
+ $actionName = $aActions[$end];
+
+ // create a new element in the array for the page
+ // we are careful to prefix the pageName with some value so that if a page has the same name
+ // as a category we don't overwrite or do other silly things
+
+ // if the page name is not a URL we add a / before
+ if( !$isUrl )
+ {
+ // we know that the concatenation of a space and the name of the action
+ // will always be unique as all the action names have been trimmed before reaching this point
+ $actionName = '/' . $actionName;
+ }
+ else
+ {
+ $actionName = ' ' . $actionName;
+ }
+
+ // currentTable is now the array element corresponding the the action
+ // at this point we may be for example at the 4th level of depth in the hierarchy
+ $currentTable =& $currentTable[$actionName];
+
+ // add the row to the matching sub category subtable
+ if(!($currentTable instanceof Piwik_DataTable_Row))
+ {
+ $currentTable = new Piwik_DataTable_Row(
+ array( Piwik_DataTable_Row::COLUMNS =>
+ array( 'label' => (string)$actionName,
+ 'full_url' => (string)$row['name'],
+ )
+ )
+ );
+ }
+
+ foreach($row as $name => $value)
+ {
+ // we don't add this information as itnot pertinent
+ // name is already set as the label // and it has been cleaned from the categories and extracted from the initial string
+ // type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate.
+ if($name != 'name' && $name != 'type')
+ {
+ // in some very rare case, we actually have twice the same action name with 2 different idaction
+ // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page,
+ // and in between the two the other visitor comes.
+ // here we handle the case where there is already a row for this action name, if this is the case we add the value
+ if(($alreadyValue = $currentTable->getColumn($name)) !== false)
+ {
+ $currentTable->setColumn($name, $alreadyValue+$value);
+ }
+ else
+ {
+ $currentTable->addColumn($name, $value);
+ }
+ }
+ }
+
+ // if the exit_action was not recorded properly in the log_link_visit_action
+ // there would be an error message when getting the nb_hits column
+ // we must fake the record and add the columns
+ if($currentTable->getColumn('nb_hits') === false)
+ {
+ // to test this code: delete the entries in log_link_action_visit for
+ // a given exit_idaction
+ foreach($this->defaultRow->getColumns() as $name => $value)
+ {
+ $currentTable->addColumn($name, $value);
+ }
+ }
+ // simple count
+ $rowsProcessed++;
+ }
+
+ // just to make sure php copies the last $currentTable in the $parentTable array
+ $currentTable =& $this->actionsTablesByType;
+
+ return $rowsProcessed;
+ }
+}
+
diff --git a/plugins/Actions/Controller.php b/plugins/Actions/Controller.php
index 4957756f3c..85d3cf9466 100644
--- a/plugins/Actions/Controller.php
+++ b/plugins/Actions/Controller.php
@@ -149,7 +149,7 @@ class Piwik_Actions_Controller extends Piwik_Controller
// and each of them has 1 or 2 hits...
$nbActionsLowPopulationThreshold = min($visitsInfo->getColumn('max_actions')-1, $nbActionsLowPopulationThreshold-1);
- $view->setExcludeLowPopulation( $nbActionsLowPopulationThreshold, 'nb_hits' );
+ $view->setExcludeLowPopulation( 'nb_hits', $nbActionsLowPopulationThreshold );
$view->main();
diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php
index 26c0875aa4..185cdfb2c2 100644
--- a/plugins/CoreHome/Controller.php
+++ b/plugins/CoreHome/Controller.php
@@ -1,26 +1,26 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: Controller.php 561 2008-07-21 00:00:35Z matt $
- *
- * @package Piwik_CoreHome
- *
- */
-
-require_once "API/Request.php";
-require_once "ViewDataTable.php";
-
-/**
- * @package Piwik_CoreHome
- */
-class Piwik_CoreHome_Controller extends Piwik_Controller
-{
- function getDefaultAction()
- {
- return 'redirectToIndex';
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Controller.php 561 2008-07-21 00:00:35Z matt $
+ *
+ * @package Piwik_CoreHome
+ *
+ */
+
+require_once "API/Request.php";
+require_once "ViewDataTable.php";
+
+/**
+ * @package Piwik_CoreHome
+ */
+class Piwik_CoreHome_Controller extends Piwik_Controller
+{
+ function getDefaultAction()
+ {
+ return 'redirectToIndex';
}
function redirectToIndex()
@@ -32,36 +32,36 @@ class Piwik_CoreHome_Controller extends Piwik_Controller
return Piwik_FrontController::dispatch('Login', false);
}
parent::redirectToIndex('CoreHome', 'index');
- }
+ }
- protected function setGeneralVariablesView($view)
- {
- parent::setGeneralVariablesView($view);
- $view->menu = Piwik_GetMenu();
- }
+ protected function setGeneralVariablesView($view)
+ {
+ parent::setGeneralVariablesView($view);
+ $view->menu = Piwik_GetMenu();
+ }
- public function showInContext()
- {
- $controllerName = Piwik_Common::getRequestVar('moduleToLoad');
- $actionName = Piwik_Common::getRequestVar('actionToLoad', 'index');
-
- $view = $this->getDefaultIndexView();
- $view->basicHtmlView = true;
- $view->content = Piwik_FrontController::getInstance()->fetchDispatch( $controllerName, $actionName );
- echo $view->render();
- }
-
- protected function getDefaultIndexView()
- {
- $view = new Piwik_View('CoreHome/templates/index.tpl');
- $this->setGeneralVariablesView($view);
+ public function showInContext()
+ {
+ $controllerName = Piwik_Common::getRequestVar('moduleToLoad');
+ $actionName = Piwik_Common::getRequestVar('actionToLoad', 'index');
+
+ $view = $this->getDefaultIndexView();
+ $view->basicHtmlView = true;
+ $view->content = Piwik_FrontController::getInstance()->fetchDispatch( $controllerName, $actionName );
+ echo $view->render();
+ }
+
+ protected function getDefaultIndexView()
+ {
+ $view = new Piwik_View('CoreHome/templates/index.tpl');
+ $this->setGeneralVariablesView($view);
$view->content = '';
- return $view;
+ return $view;
+ }
+
+ public function index()
+ {
+ $view = $this->getDefaultIndexView();
+ echo $view->render();
}
-
- public function index()
- {
- $view = $this->getDefaultIndexView();
- echo $view->render();
- }
-}
+}
diff --git a/plugins/CoreHome/templates/cloud.tpl b/plugins/CoreHome/templates/cloud.tpl
index 8989e48a85..b3c208ccc0 100644
--- a/plugins/CoreHome/templates/cloud.tpl
+++ b/plugins/CoreHome/templates/cloud.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
{literal}
<style>
diff --git a/plugins/CoreHome/templates/datatable.css b/plugins/CoreHome/templates/datatable.css
index 364e24cd69..5a3c3577a7 100644
--- a/plugins/CoreHome/templates/datatable.css
+++ b/plugins/CoreHome/templates/datatable.css
@@ -303,20 +303,6 @@ table thead div {
padding: 0.5em;
}
-#tooltip h3 {
- margin:0;
- padding:0;
-}
-#tooltip {
- position: absolute;
- z-index: 3000;
- border: 1px solid #111;
- background-color: #eee;
- opacity: 0.85;
- font-size: 0.7em;
- padding:7px;
-}
-
/* Actions table */
table.dataTableActions tr td.labelodd {
background-image: none;
diff --git a/plugins/CoreHome/templates/datatable.js b/plugins/CoreHome/templates/datatable.js
index c8b7c26079..092d203570 100644
--- a/plugins/CoreHome/templates/datatable.js
+++ b/plugins/CoreHome/templates/datatable.js
@@ -63,8 +63,7 @@ dataTable.prototype =
'filter_pattern',
'filter_column_recursive',
'filter_pattern_recursive',
- 'filter_excludelowpop',
- 'filter_excludelowpop_value',
+ 'enable_filter_excludelowpop',
'filter_offset',
'filter_limit',
'filter_sort_column',
@@ -255,19 +254,19 @@ dataTable.prototype =
.each(
function()
{
- if(typeof self.param.filter_excludelowpop == 'undefined')
+ if(typeof self.param.enable_filter_excludelowpop == 'undefined')
{
- self.param.filter_excludelowpop = 0;
+ self.param.enable_filter_excludelowpop = 0;
}
- if(Number(self.param.filter_excludelowpop) != 0)
+ if(Number(self.param.enable_filter_excludelowpop) != 0)
{
string = _pk_translate('CoreHome_IncludeAllPopulation');
- self.param.filter_excludelowpop = 1;
+ self.param.enable_filter_excludelowpop = 1;
}
else
{
string = _pk_translate('CoreHome_ExcludeLowPopulation');
- self.param.filter_excludelowpop = 0;
+ self.param.enable_filter_excludelowpop = 0;
}
$(this).html(string);
}
@@ -276,7 +275,7 @@ dataTable.prototype =
.click(
function()
{
- self.param.filter_excludelowpop = 1 - self.param.filter_excludelowpop;
+ self.param.enable_filter_excludelowpop = 1 - self.param.enable_filter_excludelowpop;
self.param.filter_offset = 0;
self.reloadAjaxDataTable(true, callbackSuccess);
}
@@ -484,6 +483,19 @@ dataTable.prototype =
}
);
+ $('#tableGoals', domElem)
+ .show()
+ .click(
+ function(){
+ // we only reset the limit filter, in case switch to table view from cloud view where limit is custom set to 30
+ // this value is stored in config file General->dataTable_default_limit but this is more an edge case so ok to set it to 10
+ delete self.param.filter_limit;
+ delete self.param.enable_filter_excludelowpop;
+ self.param.viewDataTable = 'tableGoals';
+ self.reloadAjaxDataTable();
+ }
+ );
+
$('#tableAllColumnsSwitch', domElem)
.show()
.click(
@@ -505,12 +517,17 @@ dataTable.prototype =
var method = $(this).attr('methodToCall');
var filter_limit = $(this).attr('filter_limit');
+ var param_date = self.param.date;
+ var date = $(this).attr('date');
+ if(typeof date != 'undefined') {
+ param_date = date;
+ }
var str = '?module=API'
+'&method='+method
+'&format='+format
+'&idSite='+self.param.idSite
+'&period='+self.param.period
- +'&date='+self.param.date
+ +'&date='+param_date
+'&token_auth='+piwik.token_auth;
if( filter_limit )
{
@@ -649,7 +666,7 @@ dataTable.prototype =
var filtersToRestore = self.resetAllFilters();
self.param.idSubtable = idSubTable;
- self.param.action = self.param.actionToLoadTheSubTable;
+ self.param.action = self.param.controllerActionCalledWhenRequestSubTable;
self.reloadAjaxDataTable(false);
self.param.action = savedActionVariable;
@@ -862,7 +879,7 @@ actionDataTable.prototype =
delete self.param.filter_pattern;
self.param.idSubtable = idSubTable;
- self.param.action = self.param.actionToLoadTheSubTable;
+ self.param.action = self.param.controllerActionCalledWhenRequestSubTable;
self.reloadAjaxDataTable(false, function(resp){self.actionsSubDataTableLoaded(resp)});
self.param.action = savedActionVariable;
diff --git a/plugins/CoreHome/templates/datatable.tpl b/plugins/CoreHome/templates/datatable.tpl
index 49e233f82e..55291ee9ea 100644
--- a/plugins/CoreHome/templates/datatable.tpl
+++ b/plugins/CoreHome/templates/datatable.tpl
@@ -1,12 +1,12 @@
-<div id="{$id}">
- <div class="{if isset($javascriptVariablesToSet.idSubtable)&& $javascriptVariablesToSet.idSubtable!=0}sub{/if}{if $javascriptVariablesToSet.viewDataTable=='tableAllColumns'}dataTableAllColumnsWrapper{else}dataTableWrapper{/if}">
+<div id="{$properties.uniqueId}">
+ <div class="{if isset($javascriptVariablesToSet.idSubtable)&& $javascriptVariablesToSet.idSubtable!=0}sub{/if}{if $javascriptVariablesToSet.viewDataTable=='tableAllColumns'}dataTableAllColumnsWrapper{elseif $javascriptVariablesToSet.viewDataTable=='tableGoals'}dataTableAllColumnsWrapper{else}dataTableWrapper{/if}">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
{else}
{if count($arrayDataTable) == 0}
<div id="emptyDatatable">{'CoreHome_TableNoData'|translate}</div>
{else}
- <a name="{$id}"></a>
+ <a name="{$properties.uniqueId}"></a>
<table cellspacing="0" class="dataTable">
<thead>
<tr>
@@ -18,11 +18,11 @@
<tbody>
{foreach from=$arrayDataTable item=row}
- <tr {if $row.idsubdatatable}class="subDataTable" id="{$row.idsubdatatable}"{/if}>
+ <tr {if $row.idsubdatatable && $javascriptVariablesToSet.controllerActionCalledWhenRequestSubTable != null}class="subDataTable" id="{$row.idsubdatatable}"{/if}>
{foreach from=$dataTableColumns item=column}
<td>
{if !$row.idsubdatatable && $column.name=='label' && isset($row.metadata.url)}<span id="urlLink">{$row.metadata.url}</span>{/if}
-{if $column.name=='label' && isset($row.metadata.logo)}<img {if isset($row.metadata.logoWidth)}width="{$row.metadata.logoWidth}"{/if} {if isset($row.metadata.logoHeight)}height="{$row.metadata.logoHeight}"{/if} src="{$row.metadata.logo}" />{/if}
+{if $column.name=='label'}{logoHtml metadata=$row.metadata alt=$row.columns.label}{/if}
{* sometimes all columns are not set in the datatable, we assume the value 0 *}
{if isset($row.columns[$column.name])}{$row.columns[$column.name]}{else}0{/if}
</td>
diff --git a/plugins/CoreHome/templates/datatable_actions.tpl b/plugins/CoreHome/templates/datatable_actions.tpl
index 94341cddff..c2dbe1868f 100644
--- a/plugins/CoreHome/templates/datatable_actions.tpl
+++ b/plugins/CoreHome/templates/datatable_actions.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="dataTableActionsWrapper">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
diff --git a/plugins/CoreHome/templates/datatable_actions_js.tpl b/plugins/CoreHome/templates/datatable_actions_js.tpl
index 5bf5ed2bca..568fe83d7b 100644
--- a/plugins/CoreHome/templates/datatable_actions_js.tpl
+++ b/plugins/CoreHome/templates/datatable_actions_js.tpl
@@ -1,12 +1,12 @@
<script type="text/javascript" defer="defer">
$(document).ready(function(){literal}{{/literal}
- actionDataTables['{$id}'] = new actionDataTable();
- actionDataTables['{$id}'].param = {literal}{{/literal}
+ actionDataTables['{$properties.uniqueId}'] = new actionDataTable();
+ actionDataTables['{$properties.uniqueId}'].param = {literal}{{/literal}
{foreach from=$javascriptVariablesToSet key=name item=value name=loop}
{$name}: '{$value}'{if !$smarty.foreach.loop.last},{/if}
{/foreach}
{literal}};{/literal}
- actionDataTables['{$id}'].init('{$id}');
+ actionDataTables['{$properties.uniqueId}'].init('{$properties.uniqueId}');
{literal}}{/literal});
</script>
diff --git a/plugins/CoreHome/templates/datatable_actions_recursive.tpl b/plugins/CoreHome/templates/datatable_actions_recursive.tpl
index bcec62eb2c..01a22255ed 100644
--- a/plugins/CoreHome/templates/datatable_actions_recursive.tpl
+++ b/plugins/CoreHome/templates/datatable_actions_recursive.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="dataTableActionsWrapper">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
diff --git a/plugins/CoreHome/templates/datatable_actions_subdatable.tpl b/plugins/CoreHome/templates/datatable_actions_subdatable.tpl
index 39e103f691..1cfe58edc9 100644
--- a/plugins/CoreHome/templates/datatable_actions_subdatable.tpl
+++ b/plugins/CoreHome/templates/datatable_actions_subdatable.tpl
@@ -1,4 +1,4 @@
-<tr id="{$id}"></tr>
+<tr id="{$properties.uniqueId}"></tr>
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
{else}
diff --git a/plugins/CoreHome/templates/datatable_footer.tpl b/plugins/CoreHome/templates/datatable_footer.tpl
index 355fbe2a3e..1d92fbcad5 100644
--- a/plugins/CoreHome/templates/datatable_footer.tpl
+++ b/plugins/CoreHome/templates/datatable_footer.tpl
@@ -23,10 +23,11 @@
<span id="exportToFormat" style="display:none;padding-left:4px;">
<img width="16" height="16" src="{$piwikUrl}themes/default/images/export.png" title="{'General_Export'|translate}" />
<span id="linksExportToFormat" style="display:none;">
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="CSV" filter_limit="100">CSV</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="XML" filter_limit="100">XML</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="JSON" filter_limit="100">Json</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="PHP" filter_limit="100">Php</a>
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="CSV" filter_limit="100">CSV</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="XML" filter_limit="100">XML</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="JSON" filter_limit="100">Json</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="PHP" filter_limit="100">Php</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="RSS" filter_limit="100" date="last10"><img border="0" src="{$piwikUrl}themes/default/images/feed.png"></a>
</span>
<a class="viewDataTable" format="cloud"><img width="16" height="16" src="{$piwikUrl}themes/default/images/tagcloud.png" title="{'General_TagCloud'|translate}" /></a>
<a class="viewDataTable" format="graphVerticalBar"><img width="16" height="16" src="{$piwikUrl}themes/default/images/chart_bar.png" title="{'General_VBarGraph'|translate}" /></a>
@@ -44,6 +45,13 @@
{/if}
</span>
{/if}
+ {if $properties.show_goals}
+ <span id="tableGoals" style="display:none;float:right;padding-right:4px;">
+ {if $javascriptVariablesToSet.viewDataTable != 'tableGoals'}
+ <img title="View Goals" src="{$piwikUrl}themes/default/images/goal.png" />
+ {/if}
+ </span>
+ {/if}
</span>
</div>
{/if}
diff --git a/plugins/CoreHome/templates/datatable_js.tpl b/plugins/CoreHome/templates/datatable_js.tpl
index c3e5c9e5c3..acae875cf4 100644
--- a/plugins/CoreHome/templates/datatable_js.tpl
+++ b/plugins/CoreHome/templates/datatable_js.tpl
@@ -1,13 +1,13 @@
<script type="text/javascript" defer="defer">
$(document).ready(function(){literal}{{/literal}
- dataTables['{$id}'] = new dataTable();
- dataTables['{$id}'].param = {literal}{{/literal}
+ dataTables['{$properties.uniqueId}'] = new dataTable();
+ dataTables['{$properties.uniqueId}'].param = {literal}{{/literal}
{foreach from=$javascriptVariablesToSet key=name item=value name=loop}
{$name}: '{$value}'{if !$smarty.foreach.loop.last},{/if}
{/foreach}
{literal}};{/literal}
- dataTables['{$id}'].init('{$id}');
+ dataTables['{$properties.uniqueId}'].init('{$properties.uniqueId}');
{literal}}{/literal});
</script>
diff --git a/plugins/CoreHome/templates/graph.tpl b/plugins/CoreHome/templates/graph.tpl
index 74e6df6e1f..4e2bd9cda4 100644
--- a/plugins/CoreHome/templates/graph.tpl
+++ b/plugins/CoreHome/templates/graph.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="{if $graphType=='evolution'}dataTableGraphEvolutionWrapper{else}dataTableGraphWrapper{/if}">
{$jsInvocationTag}
diff --git a/plugins/ExampleAPI/API.php b/plugins/ExampleAPI/API.php
index 40e0924cf2..ca052d42aa 100644
--- a/plugins/ExampleAPI/API.php
+++ b/plugins/ExampleAPI/API.php
@@ -35,6 +35,7 @@ class Piwik_ExampleAPI_API
public function getPiwikVersion()
{
+ Piwik::checkUserHasSomeViewAccess();
return Piwik_Version::VERSION;
}
diff --git a/plugins/ExamplePlugin/ExamplePlugin.php b/plugins/ExamplePlugin/ExamplePlugin.php
index 106a6cdbb8..a2cc37bf15 100644
--- a/plugins/ExamplePlugin/ExamplePlugin.php
+++ b/plugins/ExamplePlugin/ExamplePlugin.php
@@ -21,6 +21,24 @@ class Piwik_ExamplePlugin extends Piwik_Plugin
'version' => '0.1',
);
}
+
+ public function getListHooksRegistered()
+ {
+ return array(
+// 'Controller.renderView' => 'addUniqueVisitorsColumnToGivenReport',
+ );
+ }
+
+ function addUniqueVisitorsColumnToGivenReport($notification)
+ {
+ $view = $notification->getNotificationInfo();
+ $view = $view['view'];
+ if($view->getCurrentControllerName() == 'Referers'
+ && $view->getCurrentControllerAction() == 'getWebsites')
+ {
+ $view->addColumnToDisplay('nb_uniq_visitors');
+ }
+ }
}
// we register the widgets so they appear in the "Add a new widget" window in the dashboard
diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php
index f843263eb9..1bee5cdbbf 100644
--- a/plugins/Installation/Controller.php
+++ b/plugins/Installation/Controller.php
@@ -1,135 +1,135 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id$
- *
- * @package Piwik_Installation
- */
-
-require_once "Installation/View.php";
-
-/**
- *
- * @package Piwik_Installation
- */
-class Piwik_Installation_Controller extends Piwik_Controller
-{
- // public so plugins can add/delete installation steps
- public $steps = array(
- 'welcome',
- 'systemCheck',
- 'databaseSetup',
- 'tablesCreation',
- 'generalSetup',
- 'firstWebsiteSetup',
- 'displayJavascriptCode',
- 'finished'
- );
-
- protected $pathView = 'Installation/templates/';
-
- public function __construct()
- {
- if(!isset($_SESSION['currentStepDone']))
- {
- $_SESSION['currentStepDone'] = '';
- }
-
- Piwik_PostEvent('InstallationController.construct', $this);
- }
-
- public function getInstallationSteps()
- {
- return $this->steps;
- }
-
- function getDefaultAction()
- {
- return $this->steps[0];
- }
-
- function welcome()
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_Installation
+ */
+
+require_once "Installation/View.php";
+
+/**
+ *
+ * @package Piwik_Installation
+ */
+class Piwik_Installation_Controller extends Piwik_Controller
+{
+ // public so plugins can add/delete installation steps
+ public $steps = array(
+ 'welcome',
+ 'systemCheck',
+ 'databaseSetup',
+ 'tablesCreation',
+ 'generalSetup',
+ 'firstWebsiteSetup',
+ 'displayJavascriptCode',
+ 'finished'
+ );
+
+ protected $pathView = 'Installation/templates/';
+
+ public function __construct()
+ {
+ if(!isset($_SESSION['currentStepDone']))
+ {
+ $_SESSION['currentStepDone'] = '';
+ }
+
+ Piwik_PostEvent('InstallationController.construct', $this);
+ }
+
+ public function getInstallationSteps()
+ {
+ return $this->steps;
+ }
+
+ function getDefaultAction()
+ {
+ return $this->steps[0];
+ }
+
+ function welcome()
{
require_once "Login/Controller.php";
Piwik_Login_Controller::clearSession();
-
- $view = new Piwik_Install_View(
- $this->pathView . 'welcome.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->skipThisStep( __FUNCTION__ );
- $view->showNextStep = true;
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- function systemCheck()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'systemCheck.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- $view->infos = $this->getSystemInformation();
- $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories']));
-
- $view->showNextStep = !$view->problemWithSomeDirectories
- && $view->infos['phpVersion_ok']
- && $view->infos['pdo_ok']
- && $view->infos['pdo_mysql_ok']
-
- ;
- $_SESSION['currentStepDone'] = __FUNCTION__;
-
- echo $view->render();
- }
-
-
- function databaseSetup()
- {
- // case the user hits the back button
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
-
- $view = new Piwik_Install_View(
- $this->pathView . 'databaseSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- $view->showNextStep = false;
- require_once "FormDatabaseSetup.php";
- $form = new Piwik_Installation_FormDatabaseSetup;
-
- if($form->validate())
- {
- $dbInfos = array(
- 'host' => $form->getSubmitValue('host'),
- 'username' => $form->getSubmitValue('username'),
- 'password' => $form->getSubmitValue('password'),
- 'dbname' => $form->getSubmitValue('dbname'),
- 'tables_prefix' => $form->getSubmitValue('tables_prefix'),
- 'adapter' => Zend_Registry::get('config')->database->adapter,
- 'port' => Zend_Registry::get('config')->database->port,
- );
-
- $dbInfos['password'] = '"'.htmlspecialchars($form->getSubmitValue('password')).'"';
-
- if(($portIndex = strpos($dbInfos['host'],':')) !== false)
- {
- $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 );
- $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex);
- }
+
+ $view = new Piwik_Install_View(
+ $this->pathView . 'welcome.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+ $view->showNextStep = true;
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ echo $view->render();
+ }
+
+ function systemCheck()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'systemCheck.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $view->infos = $this->getSystemInformation();
+ $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories']));
+
+ $view->showNextStep = !$view->problemWithSomeDirectories
+ && $view->infos['phpVersion_ok']
+ && $view->infos['pdo_ok']
+ && $view->infos['pdo_mysql_ok']
+
+ ;
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+
+ echo $view->render();
+ }
+
+
+ function databaseSetup()
+ {
+ // case the user hits the back button
+ $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
+ $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
+
+ $view = new Piwik_Install_View(
+ $this->pathView . 'databaseSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $view->showNextStep = false;
+ require_once "FormDatabaseSetup.php";
+ $form = new Piwik_Installation_FormDatabaseSetup;
+
+ if($form->validate())
+ {
+ $dbInfos = array(
+ 'host' => $form->getSubmitValue('host'),
+ 'username' => $form->getSubmitValue('username'),
+ 'password' => $form->getSubmitValue('password'),
+ 'dbname' => $form->getSubmitValue('dbname'),
+ 'tables_prefix' => $form->getSubmitValue('tables_prefix'),
+ 'adapter' => Zend_Registry::get('config')->database->adapter,
+ 'port' => Zend_Registry::get('config')->database->port,
+ );
+
+ $dbInfos['password'] = '"'.htmlspecialchars($form->getSubmitValue('password')).'"';
+
+ if(($portIndex = strpos($dbInfos['host'],':')) !== false)
+ {
+ $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 );
+ $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex);
+ }
try{
try {
@@ -152,64 +152,64 @@ class Piwik_Installation_Controller extends Piwik_Controller
{
throw new Exception(vsprintf("Your MySQL version is %s but Piwik requires at least %s.", array($mysqlVersion, $minimumMysqlVersion)));
}
-
+
$_SESSION['db_infos'] = $dbInfos;
- $this->redirectToNextStep( __FUNCTION__ );
- } catch(Exception $e) {
- $view->errorMessage = $e->getMessage();
- }
- }
- $view->addForm($form);
-
- $view->infos = $this->getSystemInformation();
-
- echo $view->render();
- }
-
- function tablesCreation()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'tablesCreation.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
- $this->createDbFromSessionInformation();
-
- if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1)
- {
- Piwik::dropTables();
- $view->existingTablesDeleted = true;
-
- // when the user decides to drop the tables then we dont skip the next steps anymore
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
- }
-
- $tablesInstalled = Piwik::getTablesInstalled();
- $tablesToInstall = Piwik::getTablesNames();
-
- if(count($tablesInstalled) > 0)
- {
- $view->someTablesInstalled = true;
- $view->tablesInstalled = implode(", ", $tablesInstalled);
-
- // when the user reuses the same tables we skip the website creation step
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = true;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = true;
- }
- else
- {
- Piwik::createTables();
- Piwik::createAnonymousUser();
+ $this->redirectToNextStep( __FUNCTION__ );
+ } catch(Exception $e) {
+ $view->errorMessage = $e->getMessage();
+ }
+ }
+ $view->addForm($form);
+
+ $view->infos = $this->getSystemInformation();
+
+ echo $view->render();
+ }
+
+ function tablesCreation()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'tablesCreation.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+ $this->createDbFromSessionInformation();
+
+ if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1)
+ {
+ Piwik::dropTables();
+ $view->existingTablesDeleted = true;
+
+ // when the user decides to drop the tables then we dont skip the next steps anymore
+ $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
+ $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
+ }
+
+ $tablesInstalled = Piwik::getTablesInstalled();
+ $tablesToInstall = Piwik::getTablesNames();
+
+ if(count($tablesInstalled) > 0)
+ {
+ $view->someTablesInstalled = true;
+ $view->tablesInstalled = implode(", ", $tablesInstalled);
+
+ // when the user reuses the same tables we skip the website creation step
+ $_SESSION['skipThisStep']['firstWebsiteSetup'] = true;
+ $_SESSION['skipThisStep']['displayJavascriptCode'] = true;
+ }
+ else
+ {
+ Piwik::createTables();
+ Piwik::createAnonymousUser();
require_once "Version.php";
- require_once "Updater.php";
+ require_once "Updater.php";
$updater = new Piwik_Updater();
- $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION);
- $view->tablesCreated = true;
- $view->showNextStep = true;
- }
+ $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION);
+ $view->tablesCreated = true;
+ $view->showNextStep = true;
+ }
if(isset($_SESSION['databaseCreated'])
&& $_SESSION['databaseCreated'] === true)
@@ -218,294 +218,294 @@ class Piwik_Installation_Controller extends Piwik_Controller
$view->databaseCreated = true;
$_SESSION['databaseCreated'] = null;
}
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- function generalSetup()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'generalSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- require_once "FormGeneralSetup.php";
- $form = new Piwik_Installation_FormGeneralSetup;
-
- if($form->validate())
- {
- $superUserInfos = array(
- 'login' => $form->getSubmitValue('login'),
- 'password' => md5( $form->getSubmitValue('password') ),
- 'email' => $form->getSubmitValue('email'),
- );
-
- $_SESSION['superuser_infos'] = $superUserInfos;
- $this->redirectToNextStep( __FUNCTION__ );
- }
- $view->addForm($form);
-
- echo $view->render();
- }
-
- public function firstWebsiteSetup()
- {
-
- $view = new Piwik_Install_View(
- $this->pathView . 'firstWebsiteSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- require_once "FormFirstWebsiteSetup.php";
- $form = new Piwik_Installation_FormFirstWebsiteSetup;
-
- if( !isset($_SESSION['generalSetupSuccessMessage']))
- {
- $view->displayGeneralSetupSuccess = true;
- $_SESSION['generalSetupSuccessMessage'] = true;
- }
-
- if($form->validate())
- {
- // we setup the superuser login & password in the config that will be checked by the
- // API authentication process
- Zend_Registry::get('config')->superuser = $_SESSION['superuser_infos'];
-
- $name = urlencode($form->getSubmitValue('siteName'));
- $url = urlencode($form->getSubmitValue('url'));
-
- $this->initObjectsToCallAPI();
-
- require_once "API/Request.php";
- $request = new Piwik_API_Request("
- method=SitesManager.addSite
- &siteName=$name
- &urls=$url
- &format=original
- ");
-
- try {
- $result = $request->process();
- $_SESSION['site_idSite'] = $result;
- $_SESSION['site_name'] = $name;
- $_SESSION['site_url'] = $url;
-
- $this->redirectToNextStep( __FUNCTION__ );
- } catch(Exception $e) {
- $view->errorMessage = $e->getMessage();
- }
-
- }
- $view->addForm($form);
- echo $view->render();
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ echo $view->render();
+ }
+
+ function generalSetup()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'generalSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ require_once "FormGeneralSetup.php";
+ $form = new Piwik_Installation_FormGeneralSetup;
+
+ if($form->validate())
+ {
+ $superUserInfos = array(
+ 'login' => $form->getSubmitValue('login'),
+ 'password' => md5( $form->getSubmitValue('password') ),
+ 'email' => $form->getSubmitValue('email'),
+ );
+
+ $_SESSION['superuser_infos'] = $superUserInfos;
+ $this->redirectToNextStep( __FUNCTION__ );
+ }
+ $view->addForm($form);
+
+ echo $view->render();
}
-
- public function displayJavascriptCode()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'displayJavascriptCode.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- if( !isset($_SESSION['firstWebsiteSetupSuccessMessage']))
- {
- $view->displayfirstWebsiteSetupSuccess = true;
- $_SESSION['firstWebsiteSetupSuccessMessage'] = true;
- }
-
-
- $view->websiteName = urldecode($_SESSION['site_name']);
-
- $jsTag = Piwik::getJavascriptCode($_SESSION['site_idSite'], Piwik_Url::getCurrentUrlWithoutFileName());
-
- $view->javascriptTag = $jsTag;
- $view->showNextStep = true;
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- public function finished()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'finished.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
- $this->writeConfigFileFromSession();
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- $view->showNextStep = false;
-
- setcookie(session_name(), session_id(), 1, '/');
- @session_destroy();
- echo $view->render();
- }
-
- protected function initObjectsToCallAPI()
- {
- // connect to the database using the DB infos currently in the session
- $this->createDbFromSessionInformation();
-
- // create the fake access to grant super user privilege
- Zend_Registry::set('access', new Piwik_FakeAccess_SetSuperUser);
-
- // we need to create the logs otherwise the API request throws an exception
- Piwik::createLogObject();
- }
-
- protected function writeConfigFileFromSession()
+
+ public function firstWebsiteSetup()
+ {
+
+ $view = new Piwik_Install_View(
+ $this->pathView . 'firstWebsiteSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ require_once "FormFirstWebsiteSetup.php";
+ $form = new Piwik_Installation_FormFirstWebsiteSetup;
+
+ if( !isset($_SESSION['generalSetupSuccessMessage']))
+ {
+ $view->displayGeneralSetupSuccess = true;
+ $_SESSION['generalSetupSuccessMessage'] = true;
+ }
+
+ if($form->validate())
+ {
+ // we setup the superuser login & password in the config that will be checked by the
+ // API authentication process
+ Zend_Registry::get('config')->superuser = $_SESSION['superuser_infos'];
+
+ $name = urlencode($form->getSubmitValue('siteName'));
+ $url = urlencode($form->getSubmitValue('url'));
+
+ $this->initObjectsToCallAPI();
+
+ require_once "API/Request.php";
+ $request = new Piwik_API_Request("
+ method=SitesManager.addSite
+ &siteName=$name
+ &urls=$url
+ &format=original
+ ");
+
+ try {
+ $result = $request->process();
+ $_SESSION['site_idSite'] = $result;
+ $_SESSION['site_name'] = $name;
+ $_SESSION['site_url'] = $url;
+
+ $this->redirectToNextStep( __FUNCTION__ );
+ } catch(Exception $e) {
+ $view->errorMessage = $e->getMessage();
+ }
+
+ }
+ $view->addForm($form);
+ echo $view->render();
+ }
+
+ public function displayJavascriptCode()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'displayJavascriptCode.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ if( !isset($_SESSION['firstWebsiteSetupSuccessMessage']))
+ {
+ $view->displayfirstWebsiteSetupSuccess = true;
+ $_SESSION['firstWebsiteSetupSuccessMessage'] = true;
+ }
+
+
+ $view->websiteName = urldecode($_SESSION['site_name']);
+
+ $jsTag = Piwik::getJavascriptCode($_SESSION['site_idSite'], Piwik_Url::getCurrentUrlWithoutFileName());
+
+ $view->javascriptTag = $jsTag;
+ $view->showNextStep = true;
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ echo $view->render();
+ }
+
+ public function finished()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'finished.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+ $this->writeConfigFileFromSession();
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ $view->showNextStep = false;
+
+ setcookie(session_name(), session_id(), 1, '/');
+ @session_destroy();
+ echo $view->render();
+ }
+
+ protected function initObjectsToCallAPI()
+ {
+ // connect to the database using the DB infos currently in the session
+ $this->createDbFromSessionInformation();
+
+ // create the fake access to grant super user privilege
+ Zend_Registry::set('access', new Piwik_FakeAccess_SetSuperUser);
+
+ // we need to create the logs otherwise the API request throws an exception
+ Piwik::createLogObject();
+ }
+
+ protected function writeConfigFileFromSession()
{
if(!isset($_SESSION['superuser_infos'])
|| !isset($_SESSION['db_infos']))
{
return;
- }
- $configFile = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n";
- $configFile .= "; file automatically generated during the piwik installation process\n";
-
- // super user information
- $configFile .= "[superuser]\n";
- foreach( $_SESSION['superuser_infos'] as $key => $value)
- {
- $configFile .= "$key = $value\n";
- }
- $configFile .= "\n";
-
- // database information
- $configFile .= "[database]\n";
- foreach($_SESSION['db_infos'] as $key => $value)
- {
- $configFile .= "$key = $value\n";
- }
-
- file_put_contents(Piwik_Config::getDefaultUserConfigPath(), $configFile);
- }
- /**
- * The previous step is valid if it is either
- * - any step before (OK to go back)
- * - the current step (case when validating a form)
- */
- function checkPreviousStepIsValid( $currentStep )
+ }
+ $configFile = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n";
+ $configFile .= "; file automatically generated during the piwik installation process\n";
+
+ // super user information
+ $configFile .= "[superuser]\n";
+ foreach( $_SESSION['superuser_infos'] as $key => $value)
+ {
+ $configFile .= "$key = $value\n";
+ }
+ $configFile .= "\n";
+
+ // database information
+ $configFile .= "[database]\n";
+ foreach($_SESSION['db_infos'] as $key => $value)
+ {
+ $configFile .= "$key = $value\n";
+ }
+
+ file_put_contents(Piwik_Config::getDefaultUserConfigPath(), $configFile);
+ }
+ /**
+ * The previous step is valid if it is either
+ * - any step before (OK to go back)
+ * - the current step (case when validating a form)
+ */
+ function checkPreviousStepIsValid( $currentStep )
{
if(empty($_SESSION['currentStepDone']))
{
return;
- }
- // the currentStep
- $currentStepId = array_search($currentStep, $this->steps);
-
- // the step before
- $previousStepId = array_search($_SESSION['currentStepDone'], $this->steps);
+ }
+ // the currentStep
+ $currentStepId = array_search($currentStep, $this->steps);
+
+ // the step before
+ $previousStepId = array_search($_SESSION['currentStepDone'], $this->steps);
- // not OK if currentStepId > previous+1
- if( $currentStepId > $previousStepId + 1 )
- {
- $message = "Error: it seems you try to skip a step of the Installation process,
- or your cookies are disabled.
- <br /><b>Make sure your cookies are enabled</b> and go back
- <a href='".Piwik_Url::getCurrentUrlWithoutFileName()."'>
- to the first page of the installation</a>.";
- Piwik::exitWithErrorMessage( $message );
- }
- }
-
- protected function redirectToNextStep($currentStep)
- {
- $_SESSION['currentStepDone'] = $currentStep;
- $nextStep = $this->steps[1 + array_search($currentStep, $this->steps)];
- Piwik::redirectToModule('Installation' , $nextStep);
- }
-
- protected function createDbFromSessionInformation()
- {
- $dbInfos = $_SESSION['db_infos'];
-
- Zend_Registry::get('config')->database = $dbInfos;
- Piwik::createDatabaseObject($dbInfos);
- }
-
- protected function getSystemInformation()
- {
- $minimumPhpVersion = Zend_Registry::get('config')->General->minimum_php_version;
- $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit;
-
- $infos = array();
-
- $infos['directories'] = Piwik::checkDirectoriesWritable();
- $infos['phpVersion_minimum'] = $minimumPhpVersion;
- $infos['phpVersion'] = phpversion();
- $infos['phpVersion_ok'] = version_compare( $minimumPhpVersion, $infos['phpVersion']) === -1;
-
- $extensions = @get_loaded_extensions();
-
- $infos['pdo_ok'] = false;
- if (in_array('PDO', $extensions))
- {
- $infos['pdo_ok'] = true;
- }
-
- $infos['pdo_mysql_ok'] = false;
- if (in_array('pdo_mysql', $extensions))
- {
- $infos['pdo_mysql_ok'] = true;
- }
-
- $infos['gd_ok'] = false;
- if (in_array('gd', $extensions))
- {
- $gdInfo = gd_info();
- $infos['gd_version'] = $gdInfo['GD Version'];
- ereg ("([0-9]{1})", $gdInfo['GD Version'], $gdVersion);
- if($gdVersion[0] >= 2)
- {
- $infos['gd_ok'] = true;
- }
- }
-
- $infos['serverVersion'] = addslashes($_SERVER['SERVER_SOFTWARE']);
- $infos['serverOs'] = @php_uname();
- $infos['serverTime'] = date('H:i:s');
-
- $infos['setTimeLimit_ok'] = false;
- if(function_exists( 'set_time_limit'))
- {
- $infos['setTimeLimit_ok'] = true;
- }
-
- $infos['mail_ok'] = false;
- if(function_exists('mail'))
- {
- $infos['mail_ok'] = true;
- }
-
- $infos['registerGlobals_ok'] = ini_get('register_globals') == 0;
- $infos['memoryMinimum'] = $minimumMemoryLimit;
-
- $infos['memory_ok'] = true;
- // on windows the ini_get is not working?
- $infos['memoryCurrent'] = '?M';
-
- $raised = Piwik::raiseMemoryLimitIfNecessary();
- if( $memoryValue = Piwik::getMemoryLimitValue() )
- {
- $infos['memoryCurrent'] = $memoryValue."M";
- $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit;
- }
-
- return $infos;
+ // not OK if currentStepId > previous+1
+ if( $currentStepId > $previousStepId + 1 )
+ {
+ $message = "Error: it seems you try to skip a step of the Installation process,
+ or your cookies are disabled.
+ <br /><b>Make sure your cookies are enabled</b> and go back
+ <a href='".Piwik_Url::getCurrentUrlWithoutFileName()."'>
+ to the first page of the installation</a>.";
+ Piwik::exitWithErrorMessage( $message );
+ }
+ }
+
+ protected function redirectToNextStep($currentStep)
+ {
+ $_SESSION['currentStepDone'] = $currentStep;
+ $nextStep = $this->steps[1 + array_search($currentStep, $this->steps)];
+ Piwik::redirectToModule('Installation' , $nextStep);
+ }
+
+ protected function createDbFromSessionInformation()
+ {
+ $dbInfos = $_SESSION['db_infos'];
+
+ Zend_Registry::get('config')->database = $dbInfos;
+ Piwik::createDatabaseObject($dbInfos);
+ }
+
+ protected function getSystemInformation()
+ {
+ $minimumPhpVersion = Zend_Registry::get('config')->General->minimum_php_version;
+ $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit;
+
+ $infos = array();
+
+ $infos['directories'] = Piwik::checkDirectoriesWritable();
+ $infos['phpVersion_minimum'] = $minimumPhpVersion;
+ $infos['phpVersion'] = phpversion();
+ $infos['phpVersion_ok'] = version_compare( $minimumPhpVersion, $infos['phpVersion']) === -1;
+
+ $extensions = @get_loaded_extensions();
+
+ $infos['pdo_ok'] = false;
+ if (in_array('PDO', $extensions))
+ {
+ $infos['pdo_ok'] = true;
+ }
+
+ $infos['pdo_mysql_ok'] = false;
+ if (in_array('pdo_mysql', $extensions))
+ {
+ $infos['pdo_mysql_ok'] = true;
+ }
+
+ $infos['gd_ok'] = false;
+ if (in_array('gd', $extensions))
+ {
+ $gdInfo = gd_info();
+ $infos['gd_version'] = $gdInfo['GD Version'];
+ ereg ("([0-9]{1})", $gdInfo['GD Version'], $gdVersion);
+ if($gdVersion[0] >= 2)
+ {
+ $infos['gd_ok'] = true;
+ }
+ }
+
+ $infos['serverVersion'] = addslashes($_SERVER['SERVER_SOFTWARE']);
+ $infos['serverOs'] = @php_uname();
+ $infos['serverTime'] = date('H:i:s');
+
+ $infos['setTimeLimit_ok'] = false;
+ if(function_exists( 'set_time_limit'))
+ {
+ $infos['setTimeLimit_ok'] = true;
+ }
+
+ $infos['mail_ok'] = false;
+ if(function_exists('mail'))
+ {
+ $infos['mail_ok'] = true;
+ }
+
+ $infos['registerGlobals_ok'] = ini_get('register_globals') == 0;
+ $infos['memoryMinimum'] = $minimumMemoryLimit;
+
+ $infos['memory_ok'] = true;
+ // on windows the ini_get is not working?
+ $infos['memoryCurrent'] = '?M';
+
+ $raised = Piwik::raiseMemoryLimitIfNecessary();
+ if( $memoryValue = Piwik::getMemoryLimitValue() )
+ {
+ $infos['memoryCurrent'] = $memoryValue."M";
+ $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit;
+ }
+
+ return $infos;
}
@@ -516,18 +516,18 @@ class Piwik_Installation_Controller extends Piwik_Controller
{
$this->redirectToNextStep($step);
}
- }
-}
-
-
-/**
- *
- * @package Piwik_Installation
- */
-class Piwik_FakeAccess_SetSuperUser {
- function checkUserIsSuperUser()
- {
- return true;
- }
- function loadAccess() {}
-}
+ }
+}
+
+
+/**
+ *
+ * @package Piwik_Installation
+ */
+class Piwik_FakeAccess_SetSuperUser {
+ function checkUserIsSuperUser()
+ {
+ return true;
+ }
+ function loadAccess() {}
+}
diff --git a/plugins/Provider/API.php b/plugins/Provider/API.php
index eafea2151e..074ca64994 100644
--- a/plugins/Provider/API.php
+++ b/plugins/Provider/API.php
@@ -38,18 +38,5 @@ class Piwik_Provider_API
$dataTable->queueFilter('Piwik_DataTable_Filter_ReplaceColumnNames');
return $dataTable;
}
-
- /**
- * Example of getting a RAW BLOB
- *
- * @return blob
- */
- public function getProviderBlob( $idSite, $period, $date )
- {
- Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
- $dataTable = $archive->getBlob('Provider_hostnameExt');
- return $dataTable;
- }
}
diff --git a/plugins/Provider/Controller.php b/plugins/Provider/Controller.php
index cc08f0b3e9..c585fd6e88 100644
--- a/plugins/Provider/Controller.php
+++ b/plugins/Provider/Controller.php
@@ -1,6 +1,4 @@
<?php
-require_once "ViewDataTable.php";
-
class Piwik_Provider_Controller extends Piwik_Controller
{
/**
@@ -9,7 +7,7 @@ class Piwik_Provider_Controller extends Piwik_Controller
function getProvider($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( 'Provider', __FUNCTION__, "Provider.getProvider" );
+ $view->init( $this->pluginName, __FUNCTION__, "Provider.getProvider" );
$view->setColumnsToDisplay( array('label','nb_uniq_visitors') );
$view->setSortedColumn( 1 );
diff --git a/plugins/Provider/Provider.php b/plugins/Provider/Provider.php
index a819797c31..0de4d5b8f8 100644
--- a/plugins/Provider/Provider.php
+++ b/plugins/Provider/Provider.php
@@ -97,7 +97,8 @@ class Piwik_Provider extends Piwik_Plugin
$recordName = 'Provider_hostnameExt';
$labelSQL = "location_provider";
- $tableProvider = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByProvider = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableProvider = $archiveProcessing->getDataTableFromArray($interestByProvider);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableProvider->getSerialized());
}
diff --git a/plugins/Referers/API.php b/plugins/Referers/API.php
index 5df0dfe834..ab60cc8c83 100644
--- a/plugins/Referers/API.php
+++ b/plugins/Referers/API.php
@@ -56,10 +56,10 @@ class Piwik_Referers_API
$dataTable->queueFilter('Piwik_DataTable_Filter_ColumnCallbackReplace', array('label', 'Piwik_getRefererTypeLabel'));
return $dataTable;
}
-
+
function getKeywords($idSite, $period, $date, $expanded = false)
{
- $dataTable = $this->getDataTable('Referers_searchEngineByKeyword',$idSite, $period, $date, $expanded);
+ $dataTable = $this->getDataTable('Referers_searchEngineByKeyword', $idSite, $period, $date, $expanded);
return $dataTable;
}
diff --git a/plugins/Referers/Controller.php b/plugins/Referers/Controller.php
index c76d596b19..14bb8e7185 100644
--- a/plugins/Referers/Controller.php
+++ b/plugins/Referers/Controller.php
@@ -1,10 +1,9 @@
<?php
-require_once "ViewDataTable.php";
class Piwik_Referers_Controller extends Piwik_Controller
{
function index()
{
- $view = new Piwik_View('Referers/index.tpl');
+ $view = new Piwik_View('Referers/templates/index.tpl');
$view->graphEvolutionReferers = $this->getLastDirectEntryGraph(true);
$view->nameGraphEvolutionReferers = 'ReferersgetLastDirectEntryGraph'; // must be the function name used above
@@ -40,19 +39,17 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getSearchEnginesAndKeywords()
{
- $view = new Piwik_View('Referers/searchEngines_Keywords.tpl');
+ $view = new Piwik_View('Referers/templates/searchEngines_Keywords.tpl');
$view->searchEngines = $this->getSearchEngines(true) ;
$view->keywords = $this->getKeywords(true);
echo $view->render();
}
- /**
- * Referers
- */
+
function getRefererType( $fetch = false)
{
$view = Piwik_ViewDataTable::factory('cloud');
$view->init( $this->pluginName,
- 'getRefererType',
+ __FUNCTION__,
'Referers.getRefererType'
);
$view->disableSearchBox();
@@ -68,21 +65,21 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getKeywords( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
-
- $view->init( $this->pluginName, 'getKeywords',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getKeywords',
'getSearchEnginesFromKeywordId'
);
$view->disableExcludeLowPopulation();
$view->setColumnsToDisplay( array('label','nb_visits') );
-
+ $view->enableShowGoals();
+ $view->disableSubTableWhenShowGoals();
return $this->renderView($view, $fetch);
}
function getSearchEnginesFromKeywordId( $fetch = false )
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getSearchEnginesFromKeywordId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getSearchEnginesFromKeywordId'
);
$view->disableSearchBox();
@@ -96,34 +93,36 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getSearchEngines( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getSearchEngines',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getSearchEngines',
'getKeywordsFromSearchEngineId'
);
$view->disableSearchBox();
$view->disableExcludeLowPopulation();
+ $view->enableShowGoals();
+ $view->disableSubTableWhenShowGoals();
$view->setColumnsToDisplay( array('label','nb_visits') );
return $this->renderView($view, $fetch);
}
- public function getSearchEnginesEvolution($fetch = false)
- {
- $view = Piwik_ViewDataTable::factory('graphEvolution');
- $view->init( 'Referers', __FUNCTION__, 'Referers.getSearchEngines' );
-
- $view->setColumnsToDisplay( 'nb_uniq_visitors' );
- $view->setExactPattern( array('Google','Yahoo!'), 'label');
- //$view->setExactPattern( array('Google'), 'label');
-
- return $this->renderView($view, $fetch);
- }
+ public function getSearchEnginesEvolution($fetch = false)
+ {
+ $view = Piwik_ViewDataTable::factory('graphEvolution');
+ $view->init( $this->pluginName, __FUNCTION__, 'Referers.getSearchEngines' );
+
+ $view->setColumnsToDisplay( 'nb_uniq_visitors' );
+ $view->setExactPattern( array('Google','Yahoo!'), 'label');
+ //$view->setExactPattern( array('Google'), 'label');
+
+ return $this->renderView($view, $fetch);
+ }
function getKeywordsFromSearchEngineId( $fetch = false )
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getKeywordsFromSearchEngineId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getKeywordsFromSearchEngineId'
);
$view->disableSearchBox();
@@ -136,20 +135,23 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getWebsites( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getWebsites',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getWebsites',
'getUrlsFromWebsiteId'
);
$view->disableExcludeLowPopulation();
$view->setColumnsToDisplay( array('label','nb_visits') );
$view->setLimit(10);
+ $view->enableShowGoals();
+ $view->disableSubTableWhenShowGoals();
+
return $this->renderView($view, $fetch);
}
function getCampaigns( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getCampaigns',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getCampaigns',
'getKeywordsFromCampaignId'
);
@@ -157,16 +159,15 @@ class Piwik_Referers_Controller extends Piwik_Controller
$view->disableSearchBox();
$view->disableExcludeLowPopulation();
$view->setLimit( 5 );
-
+ $view->enableShowGoals();
$view->setColumnsToDisplay( array('label','nb_visits') );
-
return $this->renderView($view, $fetch);
}
function getKeywordsFromCampaignId( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getKeywordsFromCampaignId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getKeywordsFromCampaignId'
);
@@ -180,7 +181,7 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getUrlsFromWebsiteId( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getUrlsFromWebsiteId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getUrlsFromWebsiteId'
);
$view->disableSearchBox();
@@ -198,6 +199,7 @@ class Piwik_Referers_Controller extends Piwik_Controller
&format=original
&disable_queued_filters=1";
$request = new Piwik_API_Request($requestString);
+ $view->enableShowGoals();
return $request->process();
}
diff --git a/plugins/Referers/Referers.php b/plugins/Referers/Referers.php
index fe23422512..339a75f73f 100644
--- a/plugins/Referers/Referers.php
+++ b/plugins/Referers/Referers.php
@@ -122,10 +122,22 @@ class Piwik_Referers extends Piwik_Plugin
);
}
}
-
+
+
public function archiveDay( $notification )
{
+ /**
+ * @var Piwik_ArchiveProcessing_Day
+ */
$archiveProcessing = $notification->getNotificationObject();
+
+ $this->archiveDayAggregateVisits($archiveProcessing);
+ $this->archiveDayAggregateGoals($archiveProcessing);
+ $this->archiveDayRecordInDatabase($archiveProcessing);
+ }
+
+ protected function archiveDayAggregateVisits($archiveProcessing)
+ {
$query = "SELECT referer_type,
referer_name,
referer_keyword,
@@ -135,7 +147,8 @@ class Piwik_Referers extends Piwik_Plugin
sum(visit_total_actions) as nb_actions,
max(visit_total_actions) as max_actions,
sum(visit_total_time) as sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted
FROM ".$archiveProcessing->logTable."
WHERE visit_server_date = ?
AND idsite = ?
@@ -143,111 +156,164 @@ class Piwik_Referers extends Piwik_Plugin
ORDER BY nb_visits DESC";
$query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
- $interestBySearchEngine =
- $interestByKeyword =
- $keywordBySearchEngine =
- $searchEngineByKeyword =
- $interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE] =
- $urlByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE] =
- $keywordByCampaign =
- $interestByCampaign =
- $interestByType =
- $distinctUrls[Piwik_Common::REFERER_TYPE_WEBSITE] = array();
+ $this->interestBySearchEngine =
+ $this->interestByKeyword =
+ $this->interestBySearchEngineAndKeyword =
+ $this->interestByKeywordAndSearchEngine =
+ $this->interestByWebsite =
+ $this->interestByWebsiteAndUrl =
+ $this->interestByCampaignAndKeyword =
+ $this->interestByCampaign =
+ $this->interestByType =
+ $this->distinctUrls = array();
- while($rowBefore = $query->fetch() )
+ while($row = $query->fetch() )
{
- $row = array(
- Piwik_Archive::INDEX_NB_UNIQ_VISITORS => $rowBefore['nb_uniq_visitors'],
- Piwik_Archive::INDEX_NB_VISITS => $rowBefore['nb_visits'],
- Piwik_Archive::INDEX_NB_ACTIONS => $rowBefore['nb_actions'],
- Piwik_Archive::INDEX_MAX_ACTIONS => $rowBefore['max_actions'],
- Piwik_Archive::INDEX_SUM_VISIT_LENGTH => $rowBefore['sum_visit_length'],
- Piwik_Archive::INDEX_BOUNCE_COUNT => $rowBefore['bounce_count'],
- 'referer_type' => $rowBefore['referer_type'],
- 'referer_name' => $rowBefore['referer_name'],
- 'referer_keyword' => $rowBefore['referer_keyword'],
- 'referer_url' => $rowBefore['referer_url'],
- );
-
- switch($row['referer_type'])
+ if(empty($row['referer_type']))
{
- case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE:
-
- if(!isset($interestBySearchEngine[$row['referer_name']])) $interestBySearchEngine[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- if(!isset($interestByKeyword[$row['referer_keyword']])) $interestByKeyword[$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
- if(!isset($keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']])) $keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
- if(!isset($searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']])) $searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']]= $archiveProcessing->getNewInterestRow();
-
- $archiveProcessing->updateInterestStats( $row, $interestBySearchEngine[$row['referer_name']]);
- $archiveProcessing->updateInterestStats( $row, $interestByKeyword[$row['referer_keyword']]);
- $archiveProcessing->updateInterestStats( $row, $keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']]);
- $archiveProcessing->updateInterestStats( $row, $searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']]);
- break;
-
- case Piwik_Common::REFERER_TYPE_WEBSITE:
+ $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY;
+ }
+ else
+ {
+ switch($row['referer_type'])
+ {
+ case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE:
- if(!isset($interestByWebsite[$row['referer_type']][$row['referer_name']])) $interestByWebsite[$row['referer_type']][$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $interestByWebsite[$row['referer_type']][$row['referer_name']]);
+ if(!isset($this->interestBySearchEngine[$row['referer_name']])) $this->interestBySearchEngine[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
+ if(!isset($this->interestByKeyword[$row['referer_keyword']])) $this->interestByKeyword[$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
+ if(!isset($this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
+ if(!isset($this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']])) $this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- if(!isset($urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']])) $urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']]);
-
- if(!isset($distinctUrls[$row['referer_type']][$row['referer_url']]))
- {
- $distinctUrls[$row['referer_type']][$row['referer_url']] = true;
- }
+ $archiveProcessing->updateInterestStats( $row, $this->interestBySearchEngine[$row['referer_name']]);
+ $archiveProcessing->updateInterestStats( $row, $this->interestByKeyword[$row['referer_keyword']]);
+ $archiveProcessing->updateInterestStats( $row, $this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]);
+ $archiveProcessing->updateInterestStats( $row, $this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_WEBSITE:
+
+ if(!isset($this->interestByWebsite[$row['referer_name']])) $this->interestByWebsite[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByWebsite[$row['referer_name']]);
+
+ if(!isset($this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']])) $this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]);
- break;
+ if(!isset($this->distinctUrls[$row['referer_url']]))
+ {
+ $this->distinctUrls[$row['referer_url']] = true;
+ }
+
+ break;
+
+ case Piwik_Common::REFERER_TYPE_CAMPAIGN:
+ if(!empty($row['referer_keyword']))
+ {
+ if(!isset($this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]);
+ }
+ if(!isset($this->interestByCampaign[$row['referer_name']])) $this->interestByCampaign[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByCampaign[$row['referer_name']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_DIRECT_ENTRY:
+ // direct entry are aggregated below in $this->interestByType array
+ break;
+
+ default:
+ throw new Exception("Non expected referer_type = " . $row['referer_type']);
+ break;
+ }
+ }
+ if(!isset($this->interestByType[$row['referer_type']] )) $this->interestByType[$row['referer_type']] = $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats($row, $this->interestByType[$row['referer_type']]);
+ }
+ }
+
+ protected function archiveDayAggregateGoals($archiveProcessing)
+ {
+ $query = $archiveProcessing->queryConversionsBySegment("referer_type,referer_name,referer_keyword");
+ while($row = $query->fetch() )
+ {
+ if(empty($row['referer_type']))
+ {
+ $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY;
+ }
+ else
+ {
+ switch($row['referer_type'])
+ {
+ case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE:
+ if(!isset($this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ if(!isset($this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+
+ $archiveProcessing->updateGoalStats( $row, $this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ $archiveProcessing->updateGoalStats( $row, $this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_WEBSITE:
+ if(!isset($this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats( $row, $this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_CAMPAIGN:
+ if(!empty($row['referer_keyword']))
+ {
+ if(!isset($this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats( $row, $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ }
+ if(!isset($this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats( $row, $this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ break;
- case Piwik_Common::REFERER_TYPE_CAMPAIGN:
- if(!empty($row['referer_keyword']))
- {
- if(!isset($keywordByCampaign[$row['referer_name']][$row['referer_keyword']])) $keywordByCampaign[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $keywordByCampaign[$row['referer_name']][$row['referer_keyword']]);
- }
- if(!isset($interestByCampaign[$row['referer_name']])) $interestByCampaign[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $interestByCampaign[$row['referer_name']]);
- break;
+ default:
+ throw new Exception("Non expected referer_type = " . $row['referer_type']);
+ break;
+ }
}
- if(!isset($interestByType[$row['referer_type']] )) $interestByType[$row['referer_type']] = $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats($row, $interestByType[$row['referer_type']]);
+ if(!isset($this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] )) $this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats($row, $this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
}
-
- $numberOfDistinctSearchEngines = count($keywordBySearchEngine);
- $numberOfDistinctKeywords = count($searchEngineByKeyword);
-
- $numberOfDistinctCampaigns = count($interestByCampaign);
- $numberOfDistinctWebsites = count($interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE]);
- $numberOfDistinctWebsitesUrls = count($distinctUrls[Piwik_Common::REFERER_TYPE_WEBSITE]);
-
+
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByType);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestBySearchEngine);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByKeyword);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByWebsite);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByCampaign);
+ $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->interestByCampaignAndKeyword);
+ }
+
+ protected function archiveDayRecordInDatabase($archiveProcessing)
+ {
$numericRecords = array(
- 'Referers_distinctSearchEngines' => $numberOfDistinctSearchEngines,
- 'Referers_distinctKeywords' => $numberOfDistinctKeywords,
- 'Referers_distinctCampaigns' => $numberOfDistinctCampaigns,
- 'Referers_distinctWebsites' => $numberOfDistinctWebsites,
- 'Referers_distinctWebsitesUrls' => $numberOfDistinctWebsitesUrls,
+ 'Referers_distinctSearchEngines' => count($this->interestBySearchEngineAndKeyword),
+ 'Referers_distinctKeywords' => count($this->interestByKeywordAndSearchEngine),
+ 'Referers_distinctCampaigns' => count($this->interestByCampaign),
+ 'Referers_distinctWebsites' => count($this->interestByWebsite),
+ 'Referers_distinctWebsitesUrls' => count($this->distinctUrls),
);
+
foreach($numericRecords as $name => $value)
{
$record = new Piwik_ArchiveProcessing_Record_Numeric($name, $value);
}
- $data = $archiveProcessing->getDataTableSerialized($interestByType);
+ $data = $archiveProcessing->getDataTableSerialized($this->interestByType);
$record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_type', $data);
$maximumRowsInDataTableLevelZero = 500;
$maximumRowsInSubDataTable = 50;
- $data = $archiveProcessing->getDataTablesSerialized($keywordBySearchEngine, $interestBySearchEngine, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_keywordBySearchEngine', $data);
-
- $data = $archiveProcessing->getDataTablesSerialized($searchEngineByKeyword, $interestByKeyword, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_searchEngineByKeyword', $data);
-
- $data = $archiveProcessing->getDataTablesSerialized($keywordByCampaign, $interestByCampaign, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_keywordByCampaign', $data);
+ $blobRecords = array(
+ 'Referers_keywordBySearchEngine' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestBySearchEngineAndKeyword, $this->interestBySearchEngine),
+ 'Referers_searchEngineByKeyword' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByKeywordAndSearchEngine, $this->interestByKeyword),
+ 'Referers_keywordByCampaign' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByCampaignAndKeyword, $this->interestByCampaign),
+ 'Referers_urlByWebsite' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByWebsiteAndUrl, $this->interestByWebsite),
+ );
- $data = $archiveProcessing->getDataTablesSerialized($urlByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE], $interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE], $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_urlByWebsite', $data);
+ foreach($blobRecords as $recordName => $table )
+ {
+ $dataToRecord = $table->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $dataToRecord);
+ }
}
}
diff --git a/plugins/Referers/functions.php b/plugins/Referers/functions.php
index 9df808e0b1..735e7865e1 100644
--- a/plugins/Referers/functions.php
+++ b/plugins/Referers/functions.php
@@ -63,4 +63,5 @@ function Piwik_getRefererTypeLabel($label)
break;
}
return Piwik_Translate($indexTranslation);
-} \ No newline at end of file
+}
+
diff --git a/plugins/Referers/index.tpl b/plugins/Referers/templates/index.tpl
index df1995c81e..df1995c81e 100644
--- a/plugins/Referers/index.tpl
+++ b/plugins/Referers/templates/index.tpl
diff --git a/plugins/Referers/searchEngines_Keywords.tpl b/plugins/Referers/templates/searchEngines_Keywords.tpl
index a664aefb50..a664aefb50 100644
--- a/plugins/Referers/searchEngines_Keywords.tpl
+++ b/plugins/Referers/templates/searchEngines_Keywords.tpl
diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php
index 29e7f56b07..a2395620f8 100644
--- a/plugins/UserCountry/Controller.php
+++ b/plugins/UserCountry/Controller.php
@@ -19,39 +19,41 @@ class Piwik_UserCountry_Controller extends Piwik_Controller
function getCountry( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( 'UserCountry', __FUNCTION__, "UserCountry.getCountry" );
+ $view->init( $this->pluginName, __FUNCTION__, "UserCountry.getCountry" );
$view->disableExcludeLowPopulation();
$view->setColumnsToDisplay( array('label','nb_uniq_visitors') );
$view->setSortedColumn( 1 );
$view->disableSearchBox();
$view->setLimit( 5 );
+ $view->enableShowGoals();
return $this->renderView($view, $fetch);
}
- function getNumberOfDistinctCountries( $fetch = false)
- {
- return $this->getNumericValue('UserCountry.getNumberOfDistinctCountries');
- }
-
- function getLastDistinctCountriesGraph( $fetch = false )
- {
- $view = $this->getLastUnitGraph('UserCountry',__FUNCTION__, "UserCountry.getNumberOfDistinctCountries");
- return $this->renderView($view, $fetch);
- }
-
function getContinent( $fetch = false)
{
$view = Piwik_ViewDataTable::factory( 'graphVerticalBar' );
- $view->init( 'UserCountry', __FUNCTION__, "UserCountry.getContinent" );
+ $view->init( $this->pluginName, __FUNCTION__, "UserCountry.getContinent" );
$view->disableExcludeLowPopulation();
$view->disableSearchBox();
$view->disableOffsetInformation();
$view->disableSort();
$view->setColumnsToDisplay( array('label','nb_uniq_visitors') );
$view->setSortedColumn( 1 );
+ $view->enableShowGoals();
return $this->renderView($view, $fetch);
}
+
+ function getNumberOfDistinctCountries( $fetch = false)
+ {
+ return $this->getNumericValue('UserCountry.getNumberOfDistinctCountries');
+ }
+
+ function getLastDistinctCountriesGraph( $fetch = false )
+ {
+ $view = $this->getLastUnitGraph('UserCountry',__FUNCTION__, "UserCountry.getNumberOfDistinctCountries");
+ return $this->renderView($view, $fetch);
+ }
}
diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php
index bd69f64067..93a052ca1e 100644
--- a/plugins/UserCountry/UserCountry.php
+++ b/plugins/UserCountry/UserCountry.php
@@ -68,17 +68,42 @@ class Piwik_UserCountry extends Piwik_Plugin
function archiveDay($notification)
{
$archiveProcessing = $notification->getNotificationObject();
-
- $recordName = 'UserCountry_country';
+ $this->archiveDayAggregateVisits($archiveProcessing);
+ $this->archiveDayAggregateGoals($archiveProcessing);
+ $this->archiveDayRecordInDatabase($archiveProcessing);
+ }
+
+ protected function archiveDayAggregateVisits($archiveProcessing)
+ {
$labelSQL = "location_country";
- $tableCountry = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $record = new Piwik_ArchiveProcessing_Record_Numeric('UserCountry_distinctCountries', $tableCountry->getRowsCount());
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableCountry->getSerialized());
-
- $recordName = 'UserCountry_continent';
+ $this->interestByCountry = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+
$labelSQL = "location_continent";
- $tableContinent = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableContinent->getSerialized());
+ $this->interestByContinent = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ }
+
+ protected function archiveDayAggregateGoals($archiveProcessing)
+ {
+ $query = $archiveProcessing->queryConversionsBySegment("location_continent,location_country");
+ while($row = $query->fetch() )
+ {
+ if(!isset($this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ if(!isset($this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats($row, $this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ $archiveProcessing->updateGoalStats($row, $this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ }
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByCountry);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByContinent);
+ }
+
+ protected function archiveDayRecordInDatabase($archiveProcessing)
+ {
+ $tableCountry = $archiveProcessing->getDataTableFromArray($this->interestByCountry);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('UserCountry_country', $tableCountry->getSerialized());
+ $record = new Piwik_ArchiveProcessing_Record_Numeric('UserCountry_distinctCountries', $tableCountry->getRowsCount());
+
+ $tableContinent = $archiveProcessing->getDataTableFromArray($this->interestByContinent);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('UserCountry_continent', $tableContinent->getSerialized());
}
}
diff --git a/plugins/UserSettings/UserSettings.php b/plugins/UserSettings/UserSettings.php
index 1b64be1415..b56ed2d8b2 100644
--- a/plugins/UserSettings/UserSettings.php
+++ b/plugins/UserSettings/UserSettings.php
@@ -78,17 +78,20 @@ class Piwik_UserSettings extends Piwik_Plugin
$recordName = 'UserSettings_configuration';
$labelSQL = "CONCAT(config_os, ';', config_browser_name, ';', config_resolution)";
- $tableConfiguration = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByConfiguration = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableConfiguration = $archiveProcessing->getDataTableFromArray($interestByConfiguration);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableConfiguration->getSerialized());
$recordName = 'UserSettings_os';
$labelSQL = "config_os";
- $tableOs = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByOs = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableOs = $archiveProcessing->getDataTableFromArray($interestByOs);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableOs->getSerialized());
$recordName = 'UserSettings_browser';
$labelSQL = "CONCAT(config_browser_name, ';', config_browser_version)";
- $tableBrowser = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByBrowser = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableBrowser = $archiveProcessing->getDataTableFromArray($interestByBrowser);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableBrowser->getSerialized());
$recordName = 'UserSettings_browserType';
@@ -97,7 +100,8 @@ class Piwik_UserSettings extends Piwik_Plugin
$recordName = 'UserSettings_resolution';
$labelSQL = "config_resolution";
- $tableResolution = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByResolution = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableResolution = $archiveProcessing->getDataTableFromArray($interestByResolution);
$filter = new Piwik_DataTable_Filter_ColumnCallbackDeleteRow($tableResolution, 'label', 'Piwik_UserSettings_keepStrlenGreater');
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableResolution->getSerialized());
diff --git a/plugins/VisitFrequency/API.php b/plugins/VisitFrequency/API.php
index 06acc4090f..70e6010a02 100644
--- a/plugins/VisitFrequency/API.php
+++ b/plugins/VisitFrequency/API.php
@@ -36,6 +36,7 @@ class Piwik_VisitFrequency_API
'max_actions_returning',
'sum_visit_length_returning',
'bounce_count_returning',
+ 'nb_visits_converted_returning',
);
$dataTable = $archive->getDataTableFromNumeric($toFetch);
return $dataTable;
@@ -73,4 +74,9 @@ class Piwik_VisitFrequency_API
{
return $this->getNumeric( $idSite, $period, $date, 'bounce_count_returning');
}
+
+ public function getConvertedVisitsReturning( $idSite, $period, $date )
+ {
+ return $this->getNumeric( $idSite, $period, $date, 'nb_visits_converted_returning');
+ }
}
diff --git a/plugins/VisitFrequency/Controller.php b/plugins/VisitFrequency/Controller.php
index c3ce1a01bb..366ed17ab4 100644
--- a/plugins/VisitFrequency/Controller.php
+++ b/plugins/VisitFrequency/Controller.php
@@ -37,8 +37,7 @@ class Piwik_VisitFrequency_Controller extends Piwik_Controller
protected function getSummary()
{
- $requestString = "method=VisitFrequency.getSummary
- &format=original";
+ $requestString = "method=VisitFrequency.getSummary&format=original";
$request = new Piwik_API_Request($requestString);
return $request->process();
}
diff --git a/plugins/VisitFrequency/VisitFrequency.php b/plugins/VisitFrequency/VisitFrequency.php
index 94aa1329d9..68bb7fb02a 100644
--- a/plugins/VisitFrequency/VisitFrequency.php
+++ b/plugins/VisitFrequency/VisitFrequency.php
@@ -58,6 +58,7 @@ class Piwik_VisitFrequency extends Piwik_Plugin
'nb_actions_returning',
'sum_visit_length_returning',
'bounce_count_returning',
+ 'nb_visits_converted_returning',
);
$archiveProcessing->archiveNumericValuesSum($numericToSum);
$archiveProcessing->archiveNumericValuesMax('max_actions_returning');
@@ -72,7 +73,8 @@ class Piwik_VisitFrequency extends Piwik_Plugin
sum(visit_total_actions) as nb_actions_returning,
max(visit_total_actions) as max_actions_returning,
sum(visit_total_time) as sum_visit_length_returning,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count_returning
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count_returning,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted_returning
FROM ".$archiveProcessing->logTable."
WHERE visit_server_date = ?
AND idsite = ?
@@ -87,6 +89,7 @@ class Piwik_VisitFrequency extends Piwik_Plugin
$row['max_actions_returning'] = 0;
$row['sum_visit_length_returning'] = 0;
$row['bounce_count_returning'] = 0;
+ $row['nb_visits_converted_returning'] = 0;
}
foreach($row as $name => $value)
diff --git a/plugins/VisitTime/Controller.php b/plugins/VisitTime/Controller.php
index d08458a706..923c406a1e 100644
--- a/plugins/VisitTime/Controller.php
+++ b/plugins/VisitTime/Controller.php
@@ -23,6 +23,7 @@ class Piwik_VisitTime_Controller extends Piwik_Controller
$view->disableSearchBox();
$view->disableExcludeLowPopulation();
$view->disableOffsetInformation();
+ $view->enableShowGoals();
return $this->renderView($view, $fetch);
}
diff --git a/plugins/VisitTime/VisitTime.php b/plugins/VisitTime/VisitTime.php
index 0160b838c4..9ee7f006d9 100644
--- a/plugins/VisitTime/VisitTime.php
+++ b/plugins/VisitTime/VisitTime.php
@@ -52,41 +52,58 @@ class Piwik_VisitTime extends Piwik_Plugin
function archivePeriod( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
-
$dataTableToSum = array(
'VisitTime_localTime',
'VisitTime_serverTime',
);
-
$archiveProcessing->archiveDataTable($dataTableToSum);
}
public function archiveDay( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
-
- $this->archiveProcessing = $archiveProcessing;
-
- $recordName = 'VisitTime_localTime';
+ $this->archiveDayAggregateVisits($archiveProcessing);
+ $this->archiveDayAggregateGoals($archiveProcessing);
+ $this->archiveDayRecordInDatabase($archiveProcessing);
+ }
+
+ protected function archiveDayAggregateVisits($archiveProcessing)
+ {
$labelSQL = "HOUR(visitor_localtime)";
- $tableLocalTime = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $this->makeSureAllHoursAreSet($tableLocalTime);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableLocalTime->getSerialized());
+ $this->interestByLocalTime = $archiveProcessing->getArrayInterestForLabel($labelSQL);
- $recordName = 'VisitTime_serverTime';
$labelSQL = "HOUR(visit_first_action_time)";
- $tableServerTime = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $this->makeSureAllHoursAreSet($tableServerTime);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableServerTime->getSerialized());
+ $this->interestByServerTime = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ }
+
+ protected function archiveDayAggregateGoals($archiveProcessing)
+ {
+ $query = $archiveProcessing->queryConversionsBySingleSegment("HOUR(server_time)");
+ while($row = $query->fetch())
+ {
+ $this->interestByServerTime[$row['label']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getGoalRowFromQueryRow($row);
+ }
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByServerTime);
}
- private function makeSureAllHoursAreSet($table)
+ protected function archiveDayRecordInDatabase($archiveProcessing)
+ {
+ $tableLocalTime = $archiveProcessing->getDataTableFromArray($this->interestByLocalTime);
+ $this->makeSureAllHoursAreSet($tableLocalTime, $archiveProcessing);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('VisitTime_localTime', $tableLocalTime->getSerialized());
+
+ $tableServerTime = $archiveProcessing->getDataTableFromArray($this->interestByServerTime);
+ $this->makeSureAllHoursAreSet($tableServerTime, $archiveProcessing);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('VisitTime_serverTime', $tableServerTime->getSerialized());
+ }
+
+ private function makeSureAllHoursAreSet($table, $archiveProcessing)
{
for($i=0;$i<=23;$i++)
{
if($table->getRowFromLabel($i) === false)
{
- $row = $this->archiveProcessing->getNewInterestRowLabeled($i);
+ $row = $archiveProcessing->getNewInterestRowLabeled($i);
$table->addRow( $row );
}
}
diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php
index 5424ad8c2a..ed9a75df7c 100644
--- a/plugins/VisitsSummary/API.php
+++ b/plugins/VisitsSummary/API.php
@@ -36,6 +36,7 @@ class Piwik_VisitsSummary_API
'nb_actions',
'sum_visit_length',
'bounce_count',
+ 'nb_visits_converted',
);
$dataTable = $archive->getDataTableFromNumeric($toFetch);
return $dataTable;
@@ -83,4 +84,9 @@ class Piwik_VisitsSummary_API
{
return self::getNumeric( $idSite, $period, $date, 'bounce_count');
}
+
+ public function getVisitsConverted( $idSite, $period, $date )
+ {
+ return self::getNumeric( $idSite, $period, $date, 'nb_visits_converted');
+ }
}
diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php
index 4b2cc72e56..953c90a7d9 100644
--- a/plugins/VisitsSummary/Controller.php
+++ b/plugins/VisitsSummary/Controller.php
@@ -29,6 +29,7 @@ class Piwik_VisitsSummary_Controller extends Piwik_Controller
$view->sumVisitLength = $dataTableVisit->getColumn('sum_visit_length');
$view->bounceCount = $dataTableVisit->getColumn('bounce_count');
$view->maxActions = $dataTableVisit->getColumn('max_actions');
+ //TODO visits with conversion
}
function getSparklines()
diff --git a/tests/core/DataTable.test.php b/tests/core/DataTable.test.php
index 16960ae488..092fb7e7d3 100644
--- a/tests/core/DataTable.test.php
+++ b/tests/core/DataTable.test.php
@@ -256,7 +256,7 @@ class Test_Piwik_DataTable extends UnitTestCase
'test_stringint'=> "145",
"test" => 'string fake',
'super'=>array('this column has an array string that will be 0 when algorithm sums the value'),
- 'integerArrayToSum'=>array( 1=>1, 2=>10.0),
+ 'integerArrayToSum'=>array( 1 => 1, 2 => 10.0, 3 => array(1 => 2, 2 => 3)),
);
$metadata = array('logo'=> 'piwik.png',
'super'=>array('this column has an array value, amazing'));
@@ -273,7 +273,7 @@ class Test_Piwik_DataTable extends UnitTestCase
'test_stringint'=> "5",
0925824 => 'toto',
'super'=>array('this column has geagaean array value, amazing'),
- 'integerArrayToSum'=>array( 1=> 5, 2=>5.5),
+ 'integerArrayToSum'=>array( 1 => 5, 2 => 5.5, 3 => array(2 => 4)),
);
$finalRow = new Piwik_DataTable_Row( array(Piwik_DataTable_Row::COLUMNS => $columns2));
$finalRow->sumRow($row1);
@@ -283,10 +283,10 @@ class Test_Piwik_DataTable extends UnitTestCase
'test_float3'=> 1.5,
'test_stringint'=> 150, //add also strings!!
'super'=>array(0),
- 'integerArrayToSum' => array( 1=> 6, 2=>15.5),
+ 'test' => 0,
+ 'integerArrayToSum' => array( 1 => 6, 2 => 15.5, 3 => array(1 => 2, 2 => 7)),
0925824 => 'toto',
);
-
$rowWanted = new Piwik_DataTable_Row( array(Piwik_DataTable_Row::COLUMNS => $columnsWanted));
$this->assertTrue( Piwik_DataTable_Row::isEqual($rowWanted, $finalRow));
}
diff --git a/tests/core/DataTable/Renderer.test.php b/tests/core/DataTable/Renderer.test.php
index 28721ec5cd..182eec74b9 100644
--- a/tests/core/DataTable/Renderer.test.php
+++ b/tests/core/DataTable/Renderer.test.php
@@ -50,7 +50,7 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase
$subtable =
$array = array (
- array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Google&copy;', 'nb_uniq_visitors' => 11, 'nb_visits' => 11, 'nb_actions' => 17, 'max_actions' => '5', 'sum_visit_length' => 517, 'bounce_count' => 9),
+ array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Google&copy;', 'goals' => array('idgoal=1' => array('revenue'=> 5.5, 'nb_conversions' => 10)), 'nb_uniq_visitors' => 11, 'nb_visits' => 11, 'nb_actions' => 17, 'max_actions' => '5', 'sum_visit_length' => 517, 'bounce_count' => 9),
Piwik_DataTable_Row::METADATA => array('url' => 'http://www.google.com', 'logo' => './plugins/Referers/images/searchEngines/www.google.com.png'),
),
array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Yahoo!', 'nb_uniq_visitors' => 15, 'nb_visits' => 151, 'nb_actions' => 147, 'max_actions' => '50', 'sum_visit_length' => 517, 'bounce_count' => 90),
@@ -107,6 +107,12 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase
<result>
<row>
<label>Google©</label>
+ <goals>
+ <row idgoal=\'1\'>
+ <revenue>5.5</revenue>
+ <nb_conversions>10</nb_conversions>
+ </row>
+ </goals>
<nb_uniq_visitors>11</nb_uniq_visitors>
<nb_visits>11</nb_visits>
<nb_actions>17</nb_actions>
@@ -190,9 +196,9 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase
$dataTable = $this->getDataTableTest();
$render = new Piwik_DataTable_Renderer_Csv($dataTable);
$render->convertToUnicode = false;
- $expected = 'label,nb_uniq_visitors,nb_visits,nb_actions,max_actions,sum_visit_length,bounce_count,metadata_url,metadata_logo
-Google©,11,11,17,5,517,9,http://www.google.com,./plugins/Referers/images/searchEngines/www.google.com.png
-Yahoo!,15,151,147,50,517,90,http://www.yahoo.com,./plugins/Referers/images/searchEngines/www.yahoo.com.png';
+ $expected = 'label,goals_idgoal=1_revenue,goals_idgoal=1_nb_conversions,nb_uniq_visitors,nb_visits,nb_actions,max_actions,sum_visit_length,bounce_count,metadata_url,metadata_logo
+Google©,5.5,10,11,11,17,5,517,9,http://www.google.com,./plugins/Referers/images/searchEngines/www.google.com.png
+Yahoo!,,,15,151,147,50,517,90,http://www.yahoo.com,./plugins/Referers/images/searchEngines/www.yahoo.com.png';
$this->assertEqual( $expected,$render->render());
}
@@ -243,7 +249,7 @@ bounce_count,44';
{
$dataTable = $this->getDataTableTest();
$render = new Piwik_DataTable_Renderer_Json($dataTable, true);
- $expected = '[{"label":"Google&copy;","nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png","idsubdatatable":0,"subtable":[{"label":"sub1","count":1},{"label":"sub2","count":2}]}]';
+ $expected = '[{"label":"Google&copy;","goals":{"idgoal=1":{"revenue":5.5,"nb_conversions":10}},"nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png","idsubdatatable":0,"subtable":[{"label":"sub1","count":1},{"label":"sub2","count":2}]}]';
$rendered = $render->render();
$this->assertEqual( $expected,$rendered);
@@ -289,6 +295,12 @@ bounce_count,44';
0 =>
array (
'label' => 'Google&copy;',
+ 'goals' => array(
+ 'idgoal=1' => array(
+ 'revenue' => 5.5,
+ 'nb_conversions' => 10,
+ ),
+ ),
'nb_uniq_visitors' => 11,
'nb_visits' => 11,
'nb_actions' => 17,
diff --git a/tests/core/Piwik.test.php b/tests/core/Piwik.test.php
index f3313e7a81..6f53b1dcb3 100644
--- a/tests/core/Piwik.test.php
+++ b/tests/core/Piwik.test.php
@@ -29,17 +29,18 @@ class Test_Piwik extends UnitTestCase
(float)-1, (float)0 , (float)1, (float)1.5, (float)-1.5, (float)21111, (float)89898, (float)99999999999, (float)-4565656,
(int)-1, (int)0 , (int)1, (int)1.5, (int)-1.5, (int)21111, (int)89898, (int)99999999999, (int)-4565656,
'-1', '0' , '1', '1.5', '-1.5', '21111', '89898', '99999999999', '-4565656',
+ '1e3','0x123', "-1e-2",
);
foreach($valid as $toTest)
{
- $this->assertTrue(Piwik::isNumeric($toTest), $toTest." not valid!");
+ $this->assertTrue(Piwik::isNumeric($toTest), $toTest." not valid but should!");
}
}
public function test_isNumericNotValid()
{
$notvalid = array(
- '-1.0.0', '1e3','1,2', '0x123', '--1', '-.', "-1e-2", '- 1', '1-',
+ '-1.0.0', '1,2', '--1', '-.', '- 1', '1-',
);
foreach($notvalid as $toTest)
{
diff --git a/tests/datasets/referer-xss.txt b/tests/datasets/referer-xss.txt
new file mode 100644
index 0000000000..b396c04813
--- /dev/null
+++ b/tests/datasets/referer-xss.txt
@@ -0,0 +1,7 @@
+INSERT INTO `piwik_log_visit` (`idvisit`, `idsite`, `visitor_localtime`, `visitor_idcookie`, `visitor_returning`, `visit_first_action_time`, `visit_last_action_time`, `visit_server_date`, `visit_exit_idaction`, `visit_entry_idaction`, `visit_total_actions`, `visit_total_time`, `visit_goal_converted`, `referer_type`, `referer_name`, `referer_url`, `referer_keyword`, `config_md5config`, `config_os`, `config_browser_name`, `config_browser_version`, `config_resolution`, `config_pdf`, `config_flash`, `config_java`, `config_director`, `config_quicktime`, `config_realplayer`, `config_windowsmedia`, `config_cookie`, `location_ip`, `location_browser_lang`, `location_country`, `location_continent`, `location_provider`) VALUES
+(5, 1, '14:38:01', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 15:48:40', '2008-11-14 15:48:40', '2008-11-14', 2, 2, 1, 10, '', 2, 'Google', 'http://www.google.co.uk/search?hl=en&amp;q=%3Cscript%3Ealert(%27test%27);%3C/script%3E', '%3cscript%3ealert(%27test%27);%3c/script%3e', '231ea91c00491cb5e6484f00c274b037', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 0, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(15, 1, '18:03:29', 'fff3699b375db5e7cea33a58454cb8a0', 0, '2008-11-14 18:04:39', '2008-11-14 18:04:39', '2008-11-14', 2, 2, 1, 10, '', 3, 'htmlentities', 'http://example.com/&quot;&lt;script&gt;alert(''test'');&lt;/script&gt;', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(16, 1, '19:51:00', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 19:51:00', '2008-11-14 19:51:00', '2008-11-14', 5, 5, 1, 10, '', 3, 'example1.com', 'http://example.com/%22%3E%3Cscript%3Ealert(%27yo%27)%3C%2Fscript%3E', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(17, 1, '10:25:48', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 10:25:48', '2008-11-14 10:25:48', '2008-11-14', 5, 5, 1, 10, '', 3, 'urlencode', 'http://example3.com/test%3cscript%3ealert(%27test%27);%3c/script%3e', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(21, 1, '12:35:41', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 12:35:41', '2008-11-14 13:27:14', '2008-11-14', 5, 2, 26, 3093, '', 3, 'example2.com', 'http://example.com/&quot;&gt;&lt;script&gt;alert(''hi'')&lt;/script&gt;', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(53615, 1, '14:38:01', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-24 14:04:42', '2008-11-24 14:21:20', '2008-11-24', 2, 2, 3, 998, '', 3, 'localhost&lt;script&gt;alert(''test'')&lt;', 'http://localhost&lt;script&gt;alert(''test'')&lt;/script&gt;/test&lt;script&gt;alert(''test'')&lt;/script&gt;', '', '231ea91c00491cb5e6484f00c274b037', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 0, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip');
diff --git a/themes/default/common.css b/themes/default/common.css
index 353a9ab503..ead4c1d439 100644
--- a/themes/default/common.css
+++ b/themes/default/common.css
@@ -135,3 +135,19 @@ a {
color: #000000;
margin-bottom: 0px;
}
+#tooltip h3 {
+ font-weight:none;
+ font-size:1em;
+ color:#162540;
+ margin:0;
+ padding:0;
+}
+#tooltip {
+ position: absolute;
+ z-index: 3000;
+ border: 1px solid #111;
+ padding:7px;
+ background-color:#F5F7FF;
+ opacity:0.95;
+}
+
diff --git a/themes/default/images/feed.png b/themes/default/images/feed.png
new file mode 100644
index 0000000000..315c4f4fa6
--- /dev/null
+++ b/themes/default/images/feed.png
Binary files differ
diff --git a/themes/default/images/goal.png b/themes/default/images/goal.png
new file mode 100644
index 0000000000..e4bc611f87
--- /dev/null
+++ b/themes/default/images/goal.png
Binary files differ